LINQ join不使用EqualsComparer提供的Equals,而是使用GetHashCode

时间:2012-02-22 14:07:56

标签: linq join

当将EqualityComparer作为最后一个参数传递给Linq Join方法时,它没有使用它的Equals方法,它出于某种原因使用GetHashCode来比较项目。

是否可以改为使用Equals?

        var ss = new string[] { "aa", "bb", "cc" };
        var zz = new string[] { "aa", "zz", "cc" };

        var res = ss
            .Join(zz, 
                o => o, 
                i => i, 
                (i, o) => i + o, 
                new GenericEqualityComparer<String>((x,y) => x == y))
            .ToList();

2 个答案:

答案 0 :(得分:1)

IEqualityComparer<T>与对象进行比较时,它首先比较它们的哈希码。只有它们相等时,才使用Equals方法来优化比较。因此,在您的情况下,它至少应该Equals两次。

为了演示EqualityComparer的作用,我在Linqpad中创建了一个小代码片段:

void Main()
{
    var ss = new string[] { "aa1", "bb1", "cc1" };
    var zz = new string[] { "aa2", "aa3", "zz2", "cc2" };

    var res = ss.Join(zz,  o => o, i => i, (i, o) => i + o,
        new SubstringComparer()).ToList();
}

public class SubstringComparer : IEqualityComparer<string>
{
    public bool Equals(string left, string right)
    {
        string.Format("{0} - {1}", left, right).Dump();
        return left.Substring(0,2) == right.Substring(0,2);
    }

    public int GetHashCode(string value)
    {
        value.Dump();
        return value.Substring(0,2).GetHashCode();
    }
}

如果前两个字符相等,则字符串相等。输出是:

  

AA2
  AA3
  aa2 - aa3
  zz2所示
  CC2
  AA1
  aa2 - aa1
  BB1
  CC1
  cc2 - cc1

结果列表:

  

aa1aa2
  aa1aa3
  cc1cc2

你看到第一个第二个列表被比较(我不知道为什么,顺便说一下,可能是缓存的哈希码),然后是对。

因此,当您的GenericEqualityComparer 永远不会点击Equals时,它总会生成一个唯一的哈希码,我认为这应该是一个错误。如果并非总是使用Equals,则说明如下。如果你想比较器总是使用Equals,你应该让它总是返回一个相同的哈希码(当然效率很低)。

答案 1 :(得分:0)

https://stackoverflow.com/a/3719802/136967

有一个非常好的解释。基本上,使用Equals()进行比较,但Linq代码在进行处理时使用GetHashCode(),如果没有正确实现,则会给出奇怪的答案。

hth,
艾伦。