在与客户IEqualityComparer实施Group Join时遇到了一些奇怪的行为。
以下代码演示了对我来说问题的行为
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();
从MSDN上找到的文档中,我希望最后一个参数可以传递一系列内键和外键进行比较。
然而,在Func中放置断点显示i和o都以字母i开头,实际上是内部集合的两个元素,因此grouped
对象始终为空(我知道示例将始终为是空的,它只是表明问题的最小代码。)
有没有办法让GroupJoin对象使用自定义比较器?
为了完整性,这是在GroupJoin参数列表中创建的EqualityComparer:
public class EqualityComparer<T> : IEqualityComparer<T>
{
public EqualityComparer(Func<T, T, bool> cmp)
{
this.cmp = cmp;
}
public bool Equals(T x, T 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; }
}
答案 0 :(得分:2)
GroupJoin
操作首先需要构建一个查找 - 基本上是从inner
中的每个投影键到具有该键的inner
元素。这就是你被传递inner
值的原因。这种情况在“当请求第一个结果时”时会延迟发生,但此时它会消耗整个inner
。
然后,一旦构建了查找,就会流式传输outer
,一次一个元素。此时,应要求您的自定义相等比较器将内部键与外部键进行比较。事实上,当我向比较器添加日志记录时(我已重命名以避免与框架EqualityComparer<T>
类型发生冲突),我看到了:
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
现在这不是唯一可能的GroupJoin
实现,但它是一个相当明显的实现。有关详细信息,请参阅GroupJoin
上的Edulinq post。