C# IEqualityComparer重载的GroupJoin仅比较内部集合中的对象
在与客户IEqualityComparer实现组联接时,我遇到了一些奇怪的行为 下面的代码演示了我遇到的问题C# IEqualityComparer重载的GroupJoin仅比较内部集合中的对象,c#,lambda,iequalitycomparer,C#,Lambda,Iequalitycomparer,在与客户IEqualityComparer实现组联接时,我遇到了一些奇怪的行为 下面的代码演示了我遇到的问题 List<String> inner = new List<string>() { "i1", "i2" }; List<String> outer = new List<string>() { "o1", "o2" }; var grouped = outer.GroupJoin(inner, i => i, o=> o,
List<String> inner = new List<string>() { "i1", "i2" };
List<String> outer = new List<string>() { "o1", "o2" };
var grouped = outer.GroupJoin(inner, i => i, o=> o, (inKey, outCollection) => new {Key = inKey, List = outCollection},
new EqualityComparer<string>((i, o) => i == o)).ToList();
GroupJoin
操作首先需要构建一个查找-基本上是从internal
中的每个投影键到使用该键的internal
元素。这就是为什么要传递内部值。这在“当请求第一个结果时”方面是惰性的,但此时它将消耗整个internal
然后,一旦建立了查找,outer
流式传输,一次传输一个元素。此时,应要求自定义相等比较器比较内部键和外部键。事实上,当我将日志添加到您的比较器(我已重命名该比较器以避免与框架EqualityComparer
type冲突)时,我看到:
using System;
using System.Linq;
using System.Collections.Generic;
public class Test
{
public static void Main()
{
List<String> inner = new List<string>() { "i1", "i2" };
List<String> outer = new List<string>() { "o1", "o2" };
outer.GroupJoin(inner, i => i, o=> o,
(inKey, outCollection) => new {Key = inKey, List = outCollection},
new CustomEqualityComparer<string>((i, o) => i == o)).ToList();
}
}
public class CustomEqualityComparer<T> : IEqualityComparer<T>
{
public CustomEqualityComparer(Func<T, T, bool> cmp)
{
this.cmp = cmp;
}
public bool Equals(T x, T y)
{
Console.WriteLine("Comparing {0} and {1}", x, y);
return cmp(x, y);
}
public int GetHashCode(T obj)
{
// Always return 0 so that the function is called
return 0;
}
public Func<T, T, bool> cmp { get; set; }
}
现在,这不是GroupJoin
唯一可能的实现,但这是一个相当明显的实现。有关详细信息,请参见我的GroupJoin
。您的文档链接是Queryable.GroupJoin,但您正在调用Enumerable.GroupJoin。如果您使用与参数名称相反的outer
和inner
,则会让人感到困惑。seehttps://msdn.microsoft.com/en-us/library/vstudio/bb535047(v=vs.100)。aspx@Jon-谢谢!我改变了名称以使其更清晰,并查看了正确的文档页面,但我没有看到IQueryable版本和IEnumerable之间的任何区别。在代码的真实版本中,如果在IQueryable
上调用它,那么在IQueryable上调用它的结果是相同的,这很有趣,因为查询提供程序可能能够识别自定义比较器并将其转换为另一个表示形式(例如SQL)。。。或者它可能不会(包括将所有数据带到本地)。太棒了!因此,在将内部元素添加到查找表时,首先使用比较器检查内部元素是否唯一,然后将外部元素排序到组中。这解释了我在这个测试中看到的情况,但意味着我在实际实现中有一个bug。谢谢你的帮助here@CurlyPaul:它不会检查内部元素是否有唯一的键-它们可能没有。关键是创建一个匹配每个键的内部元素列表。毕竟,这是团队的一部分:)对,明白了。我想我需要另一个解决方案,因为这对我来说是行不通的,但我现在对它的工作原理有了更好的理解
using System;
using System.Linq;
using System.Collections.Generic;
public class Test
{
public static void Main()
{
List<String> inner = new List<string>() { "i1", "i2" };
List<String> outer = new List<string>() { "o1", "o2" };
outer.GroupJoin(inner, i => i, o=> o,
(inKey, outCollection) => new {Key = inKey, List = outCollection},
new CustomEqualityComparer<string>((i, o) => i == o)).ToList();
}
}
public class CustomEqualityComparer<T> : IEqualityComparer<T>
{
public CustomEqualityComparer(Func<T, T, bool> cmp)
{
this.cmp = cmp;
}
public bool Equals(T x, T y)
{
Console.WriteLine("Comparing {0} and {1}", x, y);
return cmp(x, y);
}
public int GetHashCode(T obj)
{
// Always return 0 so that the function is called
return 0;
}
public Func<T, T, bool> cmp { get; set; }
}
Comparing i1 and i2
Comparing i1 and i2
Comparing i1 and i2
Comparing i2 and o1
Comparing i1 and o1
Comparing i2 and o2
Comparing i1 and o2