2012-11-14 57 views
4

我需要用我寫的密鑰類型爲Dictionary由默認構造函數創建的`Dictionary`是否使用哈希碼?

I類閱讀documentation on MSDN about the default constructor of Dictionary

Dictionary<TKey, TValue>需要一個平等的實現來 確定鍵是否相等。此構造函數使用默認的 通用相等比較器,EqualityComparer<T>.Default。如果類型 TKey實現了System.IEquatable<T>通用接口,那麼 默認的相等比較器將使用該實現。或者,您可以通過使用接受比較器參數的構造函數來指定IEqualityComparer<T>一般 接口的實現。

這使得認爲我必須做的唯一的事情就是我的關鍵類實現System.IEquatable<T>

但是我很驚訝,System.IEquatable<T>沒有一個HashCode()方法。

那麼以這種方式創建的字典會使用哈希碼嗎?如果是,它從哪裏來?否則,我的字典是否有恆定的成本訪問操作(我不認爲沒有哈希碼就可以實現)

+1

我相信c#字典實際上使用散列法 –

+1

也讀取第二個鏈接的「備註」部分,IEquatable接口。它說:_If如果你實現'IEquatable ',你還應該重載'Object.Equals(Object)'和'GetHashCode'的基類實現,以便它們的行爲與'IEquatable .Equals'方法的行爲一致。如果你重寫了'Object.Equals(Object)',那麼你的類的靜態'Equals(System.Object,System.Object)'方法的調用也會調用你重寫的實現。這確保了所有'Equals'方法的調用返回一致的結果._ –

+0

是的,我注意到在看到Babak Naffas的回答後第二次閱讀。其實我剛接觸'.Net',看到'IEquatable'中的Equals'方法,'IEqualityComparer'中的'Equals + GetHashCode'使我認爲'Equals'和'GetHashCode'不在'Object'中在'.Net'中的類(沒有檢查,我的不好)。我沒有想到luksan的答案強調的性能問題的微妙之處,它證明了一個具有泛型參數的替代方法,因此是一個實現的通用接口。 –

回答

1

它仍然使用重寫object.GetHashCode()方法獲得的哈希碼。之所以有單獨的IEquatable<T>接口(即爲什麼默認的EqualityComparer<T>並不總是隻是調用覆蓋的object.Equals()方法來比較兩個對象)是出於性能原因 - object.Equals()需要object參數,因此實現必須將其轉換爲目標類型,然後才能執行有意義的比較(值類型也必須裝箱和取消裝箱);而IEquatable<T>.Equals()的參數已經是T類型。此性能考慮因素不適用於GetHashCode()方法,因爲它沒有參數,因此在IEquatable<T>接口上沒有任何理由存在。

1

是的,字典將使用哈希碼。字典實際上是封面下方的散列圖。

它將使用的哈希碼實現是由您的密鑰中的GetHashCode實現的哈希碼。如果您沒有自己定義實現,則哈希代碼將基於引用類型的引用以及值類型(結構)的單個字段。當使用自己的類作爲字典中的鍵時,建議執行GetHashCode

當你實現IEquatable<T>,你必須在對象覆蓋EqualsGetHashCode,以配合您的IEquatable<T>實現。它不在界面中的原因是GetHashCode已經定義在object上,所有的類都來自於它,所以它在界面中並沒有什麼區別。

如果未能實現GetHashCode所以你IEquatable<T>實現匹配,你可能會遇到你把字典中的一個關鍵,但無法再找回它,因爲散列碼不匹配的問題:當字典查找密鑰,它首先在該密鑰上調用GetHashCode。從這裏,字典派生內部bucket,該密鑰應該在。然後,它通過該特定桶中的所有密鑰,並調用Equals來查找正確的密鑰。

4

但是我很驚訝System.IEquatable沒有HashCode()方法。

這將是多餘的System.IEquatable<T>有一個hashCode方法System.Object(其中您的實現類將隱式繼承)已經提供了方法GetHashCode

0

字典(HashSet和KeyedCollections)都使用HashBuckets(用於速度)。
HashBuckets使用Int32的GetHashCode。

如果對象不相等,那麼它們必須有不同的GetHashCode。
但是兩個不相等的對象可能具有相同的GetHashCode。

如果GetHashCode相同,那麼聯合斷路器就是Equals。
GetHashCode比較速度更快 - 您想避免打破平局。

你想要一個好的(唯一的)GetHashCode。
如果對象來自數據庫,並且該表具有密鑰並且該關鍵字爲Int32(或更少),則將其用於完美的哈希碼。

如果您的對象沒有自然鍵,那麼可以使用系統GetHashCode。
但是,如果你有一個天然的鑰匙,然後使用它。

所有對象實施對象 Object Class
如果你的類不overrite的GetHashCode那麼它將來自對象。

建議不要使用Tuple或KeyValuePair作爲Key,因爲它們不會產生好的GetHashCode。很多碰撞。

相關問題