[.net] Object.GetHashCode()的默認實現


Answers

對於一個類來說,默認值本質上是參考平等,通常很好。 如果編寫一個結構,覆蓋相等(更重要的是為了避免裝箱)更為常見,但無論如何你都要寫一個結構非常罕見!

當重寫相等時,你應該總是有一個匹配的Equals()GetHashCode() (即對於兩個值,如果Equals()返回true,他們必須返回相同的散列碼,但不需要反向) - 並且這是常見的還要提供== / !=運算符,並且通常也要實現IEquatable<T>

為了生成散列碼,通常使用分解總和,因為這樣可以避免配對值的衝突 - 例如,對於基本的2場散列:

unchecked // disable overflow, for the unlikely possibility that you
{         // are compiling with overflow-checking enabled
    int hash = 27;
    hash = (13 * hash) + field1.GetHashCode();
    hash = (13 * hash) + field2.GetHashCode();
    return hash;
}

這具有以下優點:

  • {1,2}的散列與{2,1}的散列不同
  • {1,1}的散列與{2,2}的散列不一樣

等等 - 如果只使用未加權的總和或異或( ^ )等,這可能很常見。

Question

GetHashCode()的默認實現如何工作? 它是否有效且足夠好地處理結構,類,數組等等?

我試圖決定在什麼情況下我應該自己打包,在哪些情況下我可以安全地依靠默認實施來做好。 如果可能的話,我不想重新發明輪子。




一般來說,如果你重載Equals,你想覆蓋GetHashCode。 原因是因為兩者都用於比較類/結構的相等性。

在檢查Foo A,B時使用Equals;

(A == B)

既然我們知道指針不可能匹配,我們可以比較內部成員。

Equals(obj o)
{
    if (o == null) return false;
    MyType Foo = o as MyType;
    if (Foo == null) return false;
    if (Foo.Prop1 != this.Prop1) return false;

    return Foo.Prop2 == this.Prop2;
}

GetHashCode通常由散列表使用。 由類生成的哈希碼應始終與類給出狀態相同。

我通常會這樣做,

GetHashCode()
{
    int HashCode = this.GetType().ToString().GetHashCode();
    HashCode ^= this.Prop1.GetHashCode();
    etc.

    return HashCode;
}

有人會說,哈希碼應該只計算一次對象的生命週期,但我不同意這一點(我可能是錯的)。

使用對象提供的默認實現,除非你有一個類的引用相同,否則它們將不相等。 通過重寫Equals和GetHashCode,可以基於內部值而不是對象引用報告相等性。






Related