咨询区
David Basarab:
直入主题,参考如下代码:
public class Foo
{public int FooId { get; set; }public string FooName { get; set; }public override bool Equals(object obj){Foo fooItem = obj as Foo;if (fooItem == null) {return false;}return fooItem.FooId == this.FooId;}public override int GetHashCode(){// Which is preferred?return base.GetHashCode();//return this.FooId.GetHashCode();}
}
这里的 Foo
表示 table 中的 row,请问在重写 GetHashCode()
方法时我该用哪一种实现呢?
base.GetHashCode();
this.FooId.GetHashCode();
回答区
Marc Gravell:
如果你的 item 要作为 Dictionary
和 HashSet
中的key时,那重写 GetHashCode()
简直就是刚需,因为集合会根据 item 的 hashcode 对 item 进行分组,如果两个 item 的 hashcode 不一样,那么 equals 将永远不会被调用,GetHashCode()
方法应该要体现 Equals
的逻辑,比较方式大概如下:
如果
Equals
判定为相等,那么GetHashCode
必须相等。如果
GetHashCode
判定为相等,那么Equals
不一定相等。
再回到你的场景,用 return FooId
来作为 GetHashCode()
的实现是合理的。
不过作为一般场景,当 item 中有多个属性,推荐的做法是组合多个属性,代码如下:
unchecked // only needed if you're compiling with arithmetic checks enabled
{ // (the default compiler behaviour is *disabled*, so most folks won't need this)int hash = 13;hash = (hash * 7) + field1.GetHashCode();hash = (hash * 7) + field2.GetHashCode();...return hash;
}
值得一提是,上面的 hashcode 实现也解决了一个经典的 对角线冲突
问题,比如说:new Foo(3,5) != new Foo(5,3)
。
再提一点,作为 .NET 程序的惯用习惯,推荐再重写一下 ==
和 !=
操作符。
点评区
这个问题其实非常经典, Equals
和 GetHashCode
到底是什么关系呢?
我个人认为:在复杂类型的比较中, GetHashCode
永远是一等公民,Equals
才是二等公民,先判断 HashCode
是否一致,在不一致的情况下再看 Equals
是否一致?最终判断对象是否相等。
还有一点值得注意的是,GetHashCode 的实现一定要高效,完成理论上的 O(1)
复杂度,否则在 HashSet,Dictioanry
场景下会死的很惨,参考 HashSet 的 Contains 。
原文链接:https://stackoverflow.com/questions/371328/why-is-it-important-to-override-gethashcode-when-equals-method-is-overridden?rq=1