What's the relation between GetHashCode and Equals in a IEqualityComparer implementation?
我有一个从B类继承并实现
如果a的getHashCode实现返回,调试器将只到达a的equals实现断点
直觉上,我认为我应该返回收到的对象的哈希代码,但是这样做会使编译器忽略实例的equals实现。
为什么会这样?
代码演示:
1 2 3 4 5 6 7 8 9 10 11 12 13 | public class A : B, IEqualityComparer<A> { public bool Equals(A x, A y) { //my implementation... } public int GetHashCode(A obj) { //return obj.GetHashCode(); -> this makes my Equals implementation above be ignored! Why? return this.GetHashCode(); -> my Equals implementation is used } } |
听起来您使用的界面不正确。
您的类型应该简单地实现
这样地:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public class A : B, IEquatable<A> { public bool Equals(A other) { if (other == null || GetType() != other.GetType()) return false; //your implementation } public override bool Equals(object obj) { return Equals(obj as A); } public override int GetHashCode() { //your implementation } } |
然后你可以做像
另一种选择是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public class A : B // no interfaces { } public class AEqualComparer : IEqualityComparer<A> { public bool Equals(A x, A y) { //your implementation } public int GetHashCode(A x) { //your implementation } } |
有了这个其他选项,您需要
实施
实现
覆盖
这些概念很相似,但用途不同,不能部分互换。
让我用一个例子来展开,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | public class A { public string Value1 { get; set; } public int Value2 { get; set; } public override int GetHashCode() { unchecked { int hash = 17; hash = (hash * 23) + StringComparer.Ordinal.GetHashCode(this.Value1); hash = (hash * 23) + this.Value2; return hash; } } public override bool Equals(object obj) { var a = obj as A; if (a == null) { return false; } if (a.Value2 != this.Value2) { return false; } return StringComparer.Ordinal.Equals( a.Value1, this.Value1); } } |
此
1 | var distinct = aSequneceOfA.Distinct(); |
现在,假设在某些情况下,我对
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | public class AComparerInsensitive : IEqualityComparer<A> { public bool Equals(A x, A y) { if (x == null) { return y == null; } if (y == null) { return false; } if (x.Value2 != y.Value2) { return false; } return StringComparer.CurrentCultureIgnoreCase.Equals( x.Value1, y.Value1) } public int GetHashCode(A a) { if (a == null) { return 0; } unchecked { int hash = 17; hash = (hash * 23) + StringComparer.CurrentCultureIgnoreCase.GetHashCode( a.Value1); hash = (hash * 23) + a.Value2; return hash; } } } |
这样我就可以称之为
1 2 |
不同的Ingnores