簡體   English   中英

在個人類上使用字典時,為什么不必覆蓋GetHashCode?

[英]Why don't I ever have to override GetHashCode when using Dictionaries on personal classes?

它似乎總是“工作”而無需做任何事情。

我唯一能想到的是每個類都有一個Object.GetHashCode使用的隱藏的靜態標識符。 (同樣,有人知道Object.GetHashCode是如何實現的嗎?我在.NET Reflector中找不到它)

我從未覆蓋過GetHashCode但我一直在閱讀,人們說,您只需要在覆蓋Equals並為您的應用程序提供自定義相等性檢查時才這樣做,所以我想我很好嗎?

我仍然想知道魔術是如何工作的,盡管= P

它似乎總是“工作”而無需做任何事情。

您沒有告訴我們您是在使用鍵的值類型還是引用類型。

如果使用值類型,則EqualsGetHashCode的默認實現是可以的( Equals檢查字段是否相等,而GetHashCode基於字段(不一定是全部!)。 如果您使用的是引用類型,則EqualsGetHashCode的默認實現使用引用相等,這可能行不通; 這取決於你在做什么。

我唯一能想到的是每個類都有一個Object.GetHashCode使用的隱藏的靜態標識符。

否。默認值為基於值類型的字段和引用類型的引用的哈希碼。

(同樣,有人知道Object.GetHashCode是如何實現的嗎?我在.NET Reflector中找不到它)

這是一個實現細節,您永遠都不需要知道,也永遠不要依賴它。 它隨時可能改變。

我從未覆蓋過GetHashCode,但我一直在閱讀,人們說,您只需要在覆蓋Equals並為您的應用程序提供自定義相等性檢查時才這樣做,所以我想我很好嗎?

好吧,默認相等對您還好嗎? 如果沒有,覆蓋EqualsGetHashCode或implmenet IEqualityComparer<T>為你T

我仍然想知道魔術是如何工作的,盡管= P

每個對象都有EqualsGetHashCode 默認實現如下:

  1. 對於值類型, Equals值相等。
  2. 對於引用類型, Equals引用相等。
  3. 對於值類型, GetHashCode基於字段(同樣,不一定是所有字段!)。
  4. 對於引用類型, GetHashCode基於引用。

如果您使用的Dictionary構造函數的重載沒有為您的T攜帶IEqualityComparer<T> ,則它將使用EqualityComparer<T>.Default IEqualityComparer<T>僅使用EqualsGetHashCode 因此,如果您沒有覆蓋它們,則可以得到上面定義的實現。 如果覆蓋EqualsGetHashCode則將使用EqualityComparer<T>.Default

否則,將IEqualityComparer<T>的自定義實現傳遞給Dictionary的構造函數。

您是否將自定義類用作鍵或值? 如果僅將它們用於值,則它們的GetHashCode無關緊要。

如果將它們用作鍵,則哈希的質量會影響性能。 Dictionary存儲每個哈希代碼元素的列表,因為散列碼不必是唯一的。 在最壞的情況下,如果所有鍵最終都具有相同的哈希碼,則字典的查找時間將像列表O(n),而不像哈希表O(1)。

Object.GetHashCode的文檔非常清楚

GetHashCode方法的默認實現不能保證不同對象的唯一返回值...因此,不得將此方法的默認實現用作哈希目的的唯一對象標識符。

Equals()GetHashCode() (您正在繼承)的Object的實現通過引用進行比較。
Object.GetHashCode是用本機代碼實現的; 您可以在SSCLI(轉子)中看到它。

一個類的兩個不同實例通常將具有不同的哈希碼,即使它們的屬性相等。

僅當要按值比較時才需要覆蓋它們–如果要對具有相同屬性的不同實例進行相等比較。

這實際上取決於您對平等的定義。

class Person
{
    public string Name {get; set;}
}

void Test()
{
    var joe1 = new Person {Name="Joe"};
    var joe2 = new Person {Name="Joe"};

    Assert.AreNotEqual(joe1, joe2);
}

如果對相等性有不同的定義,則應重寫EqualsGetHashCode以獲得適當的行為。

哈希碼用於優化哈希表(字典)中的查找性能。 盡管哈希碼的目標是在對象實例之間盡可能減少沖突,但不能保證它們是唯一的。 目標應該是在給定這些對象的一組典型類型的情況下,int范圍之間的均等分布。

哈希表的工作方式是每個對象都實現一個函數,以計算希望在int范圍內盡可能分布的哈希碼。 兩個不同的對象可以產生相同的哈希碼,但給定對象實例的數據,則應始終產生相同的哈希碼。 因此,它們不是唯一的,不應用於平等。 哈希表分配一個大小為n(遠小於int范圍)的數組,當一個對象添加到哈希表中時,它將調用GetHashCode,然后根據分配的數組大小對其進行調制(%)。 對於表中的沖突,通常將對象列表鏈接在一起。 由於哈希碼的計算應該非常快,因此查找很快-跳轉到數組偏移並遍歷整個鏈。 數組越大(內存越大),沖突越少並且查找速度越快。

對象GetHashCode可能無法生成良好的哈希碼,因為根據定義,它對從其繼承的具體對象一無所知。 這就是為什么如果您有需要放置在字典中的自定義對象,並且想要優化查找(控制以最小的沖突創建均勻分布)的原因,則應該覆蓋GetHashCode。

如果需要比較兩個項目,則覆蓋等於。 如果您需要對象是可排序的(排序列表需要此對象),則重寫IComparable。

希望能幫助解釋差異。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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