2009-03-04 44 views
6

如果我重寫Equals和GetHashCode,我該如何決定要比較哪些字段?如果我有兩個對象,每個都有兩個字段,但Equals只檢查一個字段會發生什麼?重寫Equals()但不檢查所有字段 - 會發生什麼?

換句話說,假設我有這個類:

class EqualsTestClass 
{ 
    public string MyDescription { get; set; } 
    public int MyId { get; set; } 

    public override bool Equals(object obj) 
    { 
     EqualsTestClass eq = obj as EqualsTestClass; 
     if(eq == null) { 
      return false; 
     } else { 
      return MyId.Equals(eq.MyId); 
     } 
    } 

    public override int GetHashCode() 
    { 
     int hashcode = 23; 
     return (hashcode * 17) + MyId.GetHashCode(); 
    } 
} 

我認爲兩個對象相等如果他們有相同的身份識別碼。所以如果Id相同但描述不同,它們仍然被認爲是平等的。

我只是想知道這種方法的缺陷是什麼?當然,像這樣的構造會像預期的那樣表現:

 List<EqualsTestClass> test = new List<EqualsTestClass>(); 

     EqualsTestClass eq1 = new EqualsTestClass(); 
     eq1.MyId = 1; 
     eq1.MyDescription = "Des1"; 

     EqualsTestClass eq2 = new EqualsTestClass(); 
     eq2.MyId = 1; 
     eq2.MyDescription = "Des2"; 

     test.Add(eq1); 
     if (!test.Contains(eq2)) 
     { 
      // Will not be executed, as test.Contains is true 
      test.Add(eq2); 
     } 

由於等式2的值等於eq1,它不會被添加。但那是我控制的代碼,但我想知道框架中是否存在可能導致意外問題的代碼?

所以,我就應該總是添加所有公共領域在我的equals()方法的比較,或者是什麼,因爲一些不好的框架,那魔完全出乎意料的準則,以避免討厭的驚喜?

回答

11

原因覆蓋Equals()是您定義,這意味着什麼了兩個實例相等。在某些情況下,這意味着所有字段必須相同,但不一定。你決定。

欲瞭解更多信息,請參閱documentationpost

+0

同意,如OP,我overidden equals()方法來只檢查一個主要的ID,這就是它,它完全是程序員所說的。 – 2009-03-04 02:23:19

1

我不認爲你需要擔心在這種情況下的框架。 如果您作爲類設計器考慮如果它們共享相同的MyId,那麼該類的兩個實例是相等的,那麼您只需要在覆蓋Equals()和GetHashCode()方法中測試MyId。

1

你只需要檢查所需要的匹配,如果所有需要匹配的是ID,然後與過田野。

1

問題:如果我重寫Equals和GetHashCode,如何決定我比較哪些字段?

這取決於你所要完成的任務。如果您試圖查看對象是否完全相同,您應該比較所有對象。如果你有一些'鑰匙',你只想知道他們是否是同一個'對象',即使其他數據不同,只要檢查'鑰匙'值。

如果我有兩個對象,每個都有兩個字段,但Equals只檢查一個字段會發生什麼?

然後你將有一個平等的方法,只是檢查'鑰匙'是否是相同的,並可能有多個'平等'對象有內部差異。

1

也有人說,這是完全有效的和預期,這是究竟如何Equals已被認爲操作。所以作爲一個班級沒有問題。

作爲一個API,我會非常謹慎。請原諒我,如果不是這個意思:在這種情況下,這只是對其他人的警告。

潛在的問題是,API的用戶自然期待相同的對象「保持一致」。這不是平等合同的一部分,但它是這個詞的常識含義的一部分。這個類看起來有點像二元組,但不是一個,所以應該是明智的理由。

這樣一個明智的理由的例子是,一個字段是一個「可見的實現細節」,就像基於散列表的容器上的最大加載因子。一個有風險(儘管是誘人的)理由的例子是「因爲我之後添加了描述,並且不希望改變Equals方法以防止它破壞了某些東西」。

因此,做一些有點反直覺的事情是完全有效的,特別是如果你明確記錄行爲可能會令人驚訝。這種Equals方法必須得到支持,因爲在某個領域明顯不相關的情況下,禁止他們將是瘋狂的。但是應該清楚爲什麼創建具有相同ID和不同描述的兩個ID描述對是有意義的,但將它們都添加到使用Equals/HashCode防止重複的容器(如HashSet)是沒有意義的條目。

0

您的示例正在檢查列表(EqualsTestClass)是否包含具有相同屬性值的相同類型的對象。另一種完成此任務而不覆蓋平等的方式(以及對等的傳統理解)是使用自定義比較器。它看起來像這樣(在VB):

Public Class EqualsTestComparer 
Implements IEqualityComparer(Of EqualsTestClass) 
Public Function Equals1(ByVal x As EqualsTestClass, ByVal y As EqualsTestClass) As Boolean Implements System.Collections.Generic.IEqualityComparer(Of EqualsTestClass).Equals 
    If x.MyId = y.MyId and x.MyDescription = y.MyDescription Then 
     Return True 
    Else 
     Return False 
    End If 
End Function 

Public Function GetHashCode1(ByVal obj As EqualsTestClass) As Integer Implements System.Collections.Generic.IEqualityComparer(Of EqualsTestClass).GetHashCode 
    Return obj.ToString.ToLower.GetHashCode 
End Function  
End Class 

然後在你的日常只需使用自定義比較:

If Not test.Contains(eq2, New EqualsTestComparer) Then 
    //Do Stuff 
End if 
相關問題