2010-03-02 241 views
32

我正在使用領域模型,並且正在考慮我們必須在.NET中實現這兩種方法的各種方法。你最喜歡的策略是什麼?Equals和GetHashCode的最佳策略是什麼?

這是我目前實施:

public override bool Equals(object obj) 
    { 
     var newObj = obj as MyClass; 

     if (null != newObj) 
     { 
      return this.GetHashCode() == newObj.GetHashCode(); 
     } 
     else 
     { 
      return base.Equals(obj); 
     } 
    } 

    //Since this is an entity I can use it´s Id 
    //When I don´t have an Id I usually make a composite key of the properties 
    public override int GetHashCode() 
    { 
     return String.Format("MyClass{0}", this.Id.ToString()).GetHashCode(); 
    } 
+0

相關:http://stackoverflow.com/questions/2326288/implementing-ddd-entity-class-in-c – 2010-03-02 12:48:16

+8

你不能使用GetHashCode的結果作爲Equals中唯一的行列式 - 哈希碼可以是當物體不同時相同。在Equals中比較你的ID會更好。有關這方面的更多信息,請參閱[在C#中等式方法被重寫時覆蓋GetHashCode爲什麼非常重要?](http://stackoverflow.com/questions/371328/why-is-it-important-to-override-gethashcode-當你在等待方法被覆蓋在C) – 2010-03-02 12:52:41

+0

你應該記住,GetHashCode()主要用於代碼性能是重要的(列表O(1)查找等)。你的實現已經很慢了,但是你可以在不改變太多的情況下加快速度:'return(「MyClass」+ this.Id).GetHashCode();'(你可能想要用GetHashCode來記住) – Aidiakapi 2011-09-13 07:30:20

回答

3

假設情況是相同的,因爲哈希碼也相等是錯誤的。

我猜你的GetHashCode的實現是OK,但我通常使用的東西與此類似:

public override int GetHashCode() { 
    return object1.GetHashCode^intValue1^(intValue2 << 16); 
} 
+1

我知道它的老問題,但你能解釋一下你在這裏使用的表達式 – skjagini 2012-10-12 18:22:35

+0

@skjagini:參見[^ Operator](http://msdn.microsoft.com/en-us/library/zkacc7k1.aspx) - Exclusive或者,[<< Operator](http://msdn.microsoft.com/en-us/library/a1sway8w.aspx) - 左移。將多個數值組合在一起以獲得單個HashCode的方法很多。獨家或有效地twiddle位;但它有一些弱點。搜索GetHashCode實現,比如[this SO post](http://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode?lq=1 )。 – 2013-08-12 14:37:14

2

散列碼發生碰撞,所以我不認爲他們是比較平等的一個好辦法。您應該比較使對象「相等」的底層值。請參閱@Jon Skeet對此問題的回答:What is the best algorithm for an overridden System.Object.GetHashCode?以獲得更好的GetHashCode實現,前提是您的相等性包含多個屬性。如果它只是一個屬性,你可以重用它的哈希碼。

+0

你是對的,但在我看來,太過於謹慎。哈希代碼強調不適用於確定相等性。相同的對象必須具有相同的散列碼,但相同的散列碼可能會被不同的對象共享。正如你所說,他們可以碰撞。 – 2017-08-25 14:00:10

30

Domain-Driven Design使得實體值對象之間的區別。這是一個很好的區別,因爲它指導您如何實現Equals。

實體如果它們的ID彼此相等則相等。

值對象如果它們的所有(重要的)構成要素彼此相等,則它們是相等的。

在任何情況下,GetHashCode的實現都應基於用於確定相等性的相同值。換句話說,對於實體,散列碼應該直接從ID中計算出來,而對於數值對象,則應該從所有成分值中計算出來。

+0

您是否介意在**實體**上比較ID時使用'Equals()'方法的好處?什麼是用例?我問了[這裏的一個類似的問題](http://stackoverflow.com/q/31533276/219187),但直到現在我還沒有得到一個答案,明確說明爲什麼實體應通過ID進行比較。 – theDmi 2015-07-22 09:50:05

+0

@theDmi - 原因是實體的定義特別指它是唯一可識別的,並且可能是系統控制的。至少對於基本上包含數據和方法來更改數據的實體,每個實體都有一個標識符,並且該標識符將是唯一的。如果我使用相同的數據創建十個實體並使用相同的調用來構建它們,則身份將是唯一唯一的唯一。這就是埃文斯聲明系統可以控制身份創建的原因。就我個人而言,我總是讓實體創建標識符來支持這一點。 – 2016-08-14 05:15:30

3

這裏沒有任何答案真的給我留下了深刻的印象。既然你已經說過你不能使用Id進行平等,並且你需要使用一組屬性,這裏有一個更好的方法來做到這一點。注意:我並不認爲這是實施EqualsGetHashCode的最佳方法。這是OP代碼的更好版本。

public override bool Equals(object obj) 
{ 
    var myClass = obj as MyClass; 

    if (null != myClass) 
    { 
     // Order these by the most different first. 
     // That is, whatever value is most selective, and the fewest 
     // instances have the same value, put that first. 
     return this.Id == myClass.Id 
     && this.Name == myClass.Name 
     && this.Quantity == myClass.Quantity 
     && this.Color == myClass.Color; 
    } 
    else 
    { 
     // Not sure this makes sense! 
     return base.Equals(obj); 
    } 
} 

public override int GetHashCode() 
{ 
    int hash = 19; 
    unchecked { // allow "wrap around" in the int 
     hash = hash * 31 + this.Id; // assuming integer 
     hash = hash * 31 + this.Name.GetHashCode(); 
     hash = hash * 31 + this.Quantity; // again assuming integer 
     hash = hash * 31 + this.Color.GetHashCode(); 
    } 
    return hash; 
} 

請參閱this answer by Jon Skeet瞭解一些背後的原因。使用異或並不好,因爲各種數據集最終會導致相同的散列。帶素數的這個環繞式方法(上面的19和31的種子值,或者您選擇的其他值)可以更好地分割成每個幾乎沒有碰撞的「桶」。

如果您的任何值可以爲空,我鼓勵您仔細考慮應該如何比較。也許你可以使用短路零位評估和零合併算子。但請確保如果空值應該相等,則當它們爲空時,您可以將不同的哈希碼分配給不同的可空屬性。

此外,我不相信你的Equals實施是有道理的。當比較兩個對象時,首先比較它們的GetHashCode值。只有那些不同的是Equals方法運行(以便如果兩個哈希到相同值的對象不同,這將被檢測到)。由於您的GetHashCode實施不涉及base,因此您的Equals方法無法做到這一點。

相關問題