[英]How to write a good GetHashCode() implementation for a class that is compared by value?
假設我們有這樣一個類:
class MyClass
{
public string SomeValue { get; set; }
// ...
}
現在,假設兩個MyClass
實例的SomeValue
屬性相等。 因此,我覆蓋了Object.Equals()
和Object.GetHashCode()
方法來表示它。 Object.GetHashCode()
返回SomeValue.GetHashCode()
但同時我需要遵循以下規則:
但是很明顯, SomeValue
可以更改,並且我們之前獲得的哈希碼可能變為無效。
我只能想到使該類不可變,但是我想知道其他人在這種情況下會做什么。
在這種情況下您會怎么做? 這樣的類在設計決策中代表着一個微妙的問題嗎?
一般合同規定,如果A.equals(B)為true,則其哈希碼必須相同。 如果SomeValue在A中以A.equals(B)不再為真的方式更改,則A.GetHashCode()可以返回與以前不同的值。 可變對象無法緩存GetHashCode(),必須在每次調用該方法時對其進行計算。
本文提供了有關GetHashCode和可變性的詳細指南:
http://ericlippert.com/2011/02/28/guidelines-and-rules-for-gethashcode/
如果您的GetHashCode()
依賴於某些可變值,則只要值更改,就必須更改哈希值。 否則,您將違反平等法則。
如果您將對象放入HashSet
或作為Dictionary
的鍵,則需要有人不要求更改哈希的部分。 在這些情況下,您必須確保只要將哈希碼存儲在這樣的容器中就不會更改。 可以通過在編程時簡單地解決此問題來手動確保這一點,或者可以向對象提供一些Freeze()
方法。 如果調用此方法,則任何隨后嘗試設置屬性的嘗試都會導致某種異常(還應提供一些Defrost()
方法)。 另外,您將對Freeze()
方法的調用放入GetHashCode()
實現中,因此可以確定沒有人錯誤地更改凍結的對象。
最后一個提示:如果您需要在這樣的容器中更改對象,只需將其刪除,更改(不要忘了解凍)並再次添加即可。
您需要在可變性和為“相等”對象返回相同值的GetHashCode之間進行選擇。 通常,當您認為要對可變對象實現“相等”時,您最終會決定擁有“相等陰影”,而實際上並不意味着Object.Equals相等。
對我而言,在任何類型的數據結構中將可變對象作為“鍵”都是一個很大的危險信號。 例如:
MyObj a = new MyObj("alpha");
MyObj b = new MyObj("beta");
HashSet<MyObj> objs = new HashSet<MyObj>();
objs.Add(a);
objs.Add(b);
// objs.Count == 2
b.SomeValue = "alpha";
// objs.Distinct().Count() == 1, objs.Count == 2
我們嚴重違反了HashSet<T>
的合同。 這是一個明顯的例子,有一些微妙的例子。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.