[C#]Effective C# 條款十: 理解GetHashCode()方法的缺陷


GetHashCode對於參考類型來說,可以正常運作,但其效率很低。而對於值類型來說,其實現通常是不正確的。

GetHashCode若要重新定義,我們必須要遵循下列原則:




  1. 兩個相等的物件必須具有相同的雜湊碼。


  2. 對於任何一個物件,不論叫用甚麼方法,其GetHashCode永遠都必須返回相同的值。


  3. 對於所有輸入,雜湊函式應在所有整數中產生一隨機分佈。這樣,我們才能從一個雜湊容器獲得效率的提升。





參考類型的GetHashCode



先來看一下第一條規則。在程式未重新定義Operator==時,如果兩個物件相等,那麼Object.GetHashCode會返回同樣的雜湊值。若程式有重新定義Operator==,則我們必須跟著重新定義Object.GetHashCode方法。





而第二條規則,Object.GetHashCode預設就是永遠不會改變的。





至於第三個規則,Object.GetHashCode未能滿足此規則。除非建立了數量非常多的物件,否則其返回的雜湊值會集中在整數範圍的底端。





因此,Object.GetHashCode在功能面是正常的,但其效率不高。所以當要建立一參考型別時,我們應重新定義其GetHashCode方法,使雜湊值能在整數範圍內有良好的分佈。





值類型的GetHashCode



System.ValueType重新定義了GetHashCode方法,為值類型提供預設的實現。預設的實現會返回值類型中所定義的第一個成員的雜湊碼。





一樣的,讓我們來看一下GetHashCode重新定義要遵循的三個原則。

第一個規則對於值類型來說,絕大多數的情況下是滿足的。但我們也可能打破此規則,像是重新定義了Operator==,且未把值類型的第一個成員加入判斷條件,該條款就不會成立。





至於第二個規則,必須結構的第一個成員是一個常數型別,該規則才會被滿足。這也是為何條款七會建議”盡可能實現具有常量性的值類別”的另一個理由。





第三個規則一樣也是要看結構中的第一個成員。當第一個結構成員會在所有整數中產生一個隨機分佈,則會滿足此條款。但若是第一個結構成員經常都是相同的值,那就違反此規則。