NET问答: 重写了 Equals,还有必要重写 GetHashCode 吗?
咨詢區
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
總結
以上是生活随笔為你收集整理的NET问答: 重写了 Equals,还有必要重写 GetHashCode 吗?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用YARP当网关
- 下一篇: 在asp.net core中使用的验证框