簡體   English   中英

如何為按值比較的類編寫良好的GetHashCode()實現?

[英]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()但同時我需要遵循以下規則:

  1. 如果一個對象的兩個實例相等,則它們應返回相同的哈希碼。
  2. 哈希碼在整個運行期間不應更改。

但是很明顯, 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM