[英]Why don't I ever have to override GetHashCode when using Dictionaries on personal classes?
它似乎總是“工作”而無需做任何事情。
我唯一能想到的是每個類都有一個Object.GetHashCode
使用的隱藏的靜態標識符。 (同樣,有人知道Object.GetHashCode是如何實現的嗎?我在.NET Reflector中找不到它)
我從未覆蓋過GetHashCode
但我一直在閱讀,人們說,您只需要在覆蓋Equals並為您的應用程序提供自定義相等性檢查時才這樣做,所以我想我很好嗎?
我仍然想知道魔術是如何工作的,盡管= P
它似乎總是“工作”而無需做任何事情。
您沒有告訴我們您是在使用鍵的值類型還是引用類型。
如果使用值類型,則Equals
和GetHashCode
的默認實現是可以的( Equals
檢查字段是否相等,而GetHashCode
基於字段(不一定是全部!)。 如果您使用的是引用類型,則Equals
和GetHashCode
的默認實現使用引用相等,這可能行不通; 這取決於你在做什么。
我唯一能想到的是每個類都有一個
Object.GetHashCode
使用的隱藏的靜態標識符。
否。默認值為基於值類型的字段和引用類型的引用的哈希碼。
(同樣,有人知道Object.GetHashCode是如何實現的嗎?我在.NET Reflector中找不到它)
這是一個實現細節,您永遠都不需要知道,也永遠不要依賴它。 它隨時可能改變。
我從未覆蓋過GetHashCode,但我一直在閱讀,人們說,您只需要在覆蓋Equals並為您的應用程序提供自定義相等性檢查時才這樣做,所以我想我很好嗎?
好吧,默認相等對您還好嗎? 如果沒有,覆蓋Equals
和GetHashCode
或implmenet IEqualityComparer<T>
為你T
。
我仍然想知道魔術是如何工作的,盡管= P
每個對象都有Equals
和GetHashCode
。 默認實現如下:
Equals
值相等。 Equals
引用相等。 GetHashCode
基於字段(同樣,不一定是所有字段!)。 GetHashCode
基於引用。 如果您使用的Dictionary
構造函數的重載沒有為您的T
攜帶IEqualityComparer<T>
,則它將使用EqualityComparer<T>.Default
。 IEqualityComparer<T>
僅使用Equals
和GetHashCode
。 因此,如果您沒有覆蓋它們,則可以得到上面定義的實現。 如果覆蓋Equals
和GetHashCode
則將使用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);
}
如果對相等性有不同的定義,則應重寫Equals
和GetHashCode
以獲得適當的行為。
哈希碼用於優化哈希表(字典)中的查找性能。 盡管哈希碼的目標是在對象實例之間盡可能減少沖突,但不能保證它們是唯一的。 目標應該是在給定這些對象的一組典型類型的情況下,int范圍之間的均等分布。
哈希表的工作方式是每個對象都實現一個函數,以計算希望在int范圍內盡可能分布的哈希碼。 兩個不同的對象可以產生相同的哈希碼,但給定對象實例的數據,則應始終產生相同的哈希碼。 因此,它們不是唯一的,不應用於平等。 哈希表分配一個大小為n(遠小於int范圍)的數組,當一個對象添加到哈希表中時,它將調用GetHashCode,然后根據分配的數組大小對其進行調制(%)。 對於表中的沖突,通常將對象列表鏈接在一起。 由於哈希碼的計算應該非常快,因此查找很快-跳轉到數組偏移並遍歷整個鏈。 數組越大(內存越大),沖突越少並且查找速度越快。
對象GetHashCode可能無法生成良好的哈希碼,因為根據定義,它對從其繼承的具體對象一無所知。 這就是為什么如果您有需要放置在字典中的自定義對象,並且想要優化查找(控制以最小的沖突創建均勻分布)的原因,則應該覆蓋GetHashCode。
如果需要比較兩個項目,則覆蓋等於。 如果您需要對象是可排序的(排序列表需要此對象),則重寫IComparable。
希望能幫助解釋差異。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.