【发布时间】:2013-05-26 19:36:42
【问题描述】:
我有一个类 Foo 有两个字段,其中 Equals 和 GetHashCode 方法已被覆盖:
public class Foo
{
private readonly int _x;
private readonly int _y;
public Foo(int x, int y) { _x = x; _y = y; }
public override bool Equals(object obj) {
Foo other = obj as Foo;
return other != null && _y == other._y;
}
public override int GetHashCode() { return _y; }
}
如果我创建一个 Foo:s 数组并计算该数组的 Distinct 值的数量:
var array = new[] { new Foo(1, 1), new Foo(1, 2), new Foo(2, 2), new Foo(3, 2) };
Console.WriteLine(array.Distinct().Count());
不同值的数量被识别为:
2
如果我现在让我的班级 Foo 使用以下实现实现 IEquatable<Foo>:
public bool Equals(Foo other) { return _y == other._y; }
不同值的数量仍然是:
2
但如果我将实现更改为:
public bool Equals(Foo other) { return _x == other._x; }
计算出的不同Foo:s 的数量既不是3(即不同_x 的数量)也不是2(不同_y 的数量),但是:
4
如果我注释掉 Equals 和 GetHashCode 覆盖但保留 IEquatable<Foo> 实现,答案也是 4。
根据MSDN documentation,这个Distinct重载应该使用静态属性EqualityComparer.Default来定义相等比较,并且:
The Default property checks whether type T implements the System.IEquatable<T>
interface and, if so, returns an EqualityComparer<T> that uses that
implementation. Otherwise, it returns an EqualityComparer<T> that uses the
overrides of Object.Equals and Object.GetHashCode provided by T.
但是看上面的实验,这个说法似乎不成立。最好的情况是,IEquatable<Foo> 实现支持已经提供的Equals 和GetHashCode 覆盖,最坏的情况是它完全破坏了相等比较。
我的问题:
- 为什么
IEquatable<T>的独立实现会破坏相等比较? - 它能否独立于
Equals和GetHashCode覆盖发挥作用? - 如果不是,为什么
EqualityComparer<T>.Default会先寻找这个实现?
【问题讨论】:
标签: c# linq iequatable