为什么不.Except(LINQ)比较正确的事情?(使用IEquatable)

Gre*_*ter 26 linq

我有两个我自己的引用类型对象的集合,我编写了自己的IEquatable.Equals方法,我希望能够在它们上使用LINQ方法.

所以,

List<CandyType> candy = dataSource.GetListOfCandy();
List<CandyType> lollyPops = dataSource.GetListOfLollyPops();
var candyOtherThanLollyPops = candy.Except( lollyPops );
Run Code Online (Sandbox Code Playgroud)

根据.Except的文档,不传递IEqualityComparer应该导致EqualityComparer.Default用于比较对象.Default比较器的文档是这样的:

"Default属性检查类型T是否实现System.IEquatable泛型接口,如果是,则返回使用该实现的EqualityComparer.否则返回使用由T.提供的Object.Equals和Object.GetHashCode的覆盖的EqualityComparer."

所以,因为我为我的对象实现IEquatable,它应该使用它并且工作.但是,事实并非如此.在我覆盖GetHashCode之前它不起作用.事实上,如果我设置一个断点,我的IEquatable.Equals方法永远不会被执行.这让我认为根据其文档,它与计划B一致.我知道重写GetHashCode是一个好主意,无论如何,我可以让它工作,但我感到不安的是它的行为方式与它自己的文档所说的不一致.

它为什么不按照它所说的那样做呢?谢谢.

Gre*_*ter 20

经过调查,事实证明事情并没有我想象的那么糟糕.基本上,当一切都正确实现(GetHashCode等)时,文档是正确的,行为是正确的.但是,如果你尝试单独实现IEquatable,那么你的Equals方法永远不会被调用(这似乎是由于GetHashCode没有正确实现).因此,虽然文档在技术上是错误的,但在你从未想过要做的边缘情况下,这是唯一错误的(如果这个调查教会了我什么,那就是IEquatable是你应该原子实现的一整套方法的一部分(按照惯例,不过规则,不幸的是)).这方面的好消息是:

是否有完整的IEquatable实现引用?

http://msdn.microsoft.com/en-us/library/ms131190.aspx

http://blogs.msdn.com/irenak/archive/2006/07/18/669586.aspx


ang*_*son 11

界面IEqualityComparer<T>有以下两种方法:

bool Equals(T x, T y);
int GetHashCode(T obj);
Run Code Online (Sandbox Code Playgroud)

因此,该接口的良好实现将实现两者.Linq扩展方法除了依赖哈希代码以便在内部使用字典或设置查找以确定要跳过哪些对象,因此需要正确的GetHashCode实现.

不幸的是,当你使用EqualityComparer<T>.Default时,该类本身并不提供良好的GetHashCode实现,并且在检测到对象实现时依赖于有问题的对象T类型来提供该部分IEquatable<T>.

这里的问题是IEquatable<T>事实上并没有声明,GetHashCode因此忘记正确实现该方法要容易得多,与Equals它声明的方法形成对比.

所以你有两个选择:

  • 提供适当的IEqualityComparer<T>实现既实现EqualsGetHashCode
  • 确保除执行IEquatable<T>你的对象上,实现适当的GetHashCode,以及