2011-04-09 42 views
2

This question Jon的回答讓我意識到這個問題甚至存在,所以我很好奇並推出了Visual Studio。覆蓋類型的Equals和GetHashCode,它有'dib''?


我跟着沿MSDN頁面的一個例子,然後我創建了自己的小例子。這是如下:

public class Person : IEquatable<Person> 
{ 
    public string IdNumber { get; set; } 
    public string Name { get; set; } 

    public bool Equals(Person otherPerson) 
    { 
     if (IdNumber == otherPerson.IdNumber) 
      return true; 
     else 
      return false; 
    } 

    public override bool Equals(object obj) 
    { 
     if (obj == null) 
      return base.Equals(obj); 

     if (!(obj is Person)) 
      throw new InvalidCastException("The Object isn't of Type Person."); 
     else 
      return Equals(obj as Person); 
    } 

    public override int GetHashCode() 
    { 
     return IdNumber.GetHashCode(); 
    } 

    public static bool operator ==(Person person1, Person person2) 
    { 
     return person1.Equals(person2); 
    } 

    public static bool operator !=(Person person1, Person person2) 
    { 
     return (!person1.Equals(person2)); 
    } 
} 

所以,我有幾個問題:

  1. 如果Equals方法在處理我的自定義平等做得很好,爲什麼我必須重寫GetHashCode方法爲好?

  2. 當比較類似下面的內容時,使用哪個比較器,Equals或GetHashCode?

static void Main(string[] args) 
{ 
    Person sergio = new Person() { IdNumber = "1", Name = "Sergio" }; 
    Person lucille = new Person() { IdNumber = "2", Name = "Lucille" }; 

    List<Person> people = new List<Person>(){ 
     sergio, 
     lucille 
    }; 

    Person lucille2 = new Person() { IdNumber = "2", Name = "Lucille" }; 
    if (people.Contains(lucille2)) 
    { 
     Console.WriteLine("Already exists."); 
    } 

    Console.ReadKey(); 
} 
  1. 究竟做操作方法呢?它看起來像某種巫術黑魔法在那裏。
+0

格式化程序的行爲很奇怪。如果有人能解決這個問題,那就太好了。 :) – 2011-04-09 22:13:21

+8

如果對象是錯誤的類型,請不要拋出。如果對象是錯誤的類型,那麼*它不相等*,因此正確答案是「false」。 – 2011-04-09 22:13:29

+0

@Eric:該部分直接從MSDN示例中複製,嘿嘿。但你有道理,它應該只是返回假。 :) – 2011-04-09 22:14:21

回答

7

如果Equals方法在處理我的自定義相等性方面做得很好,爲什麼我還必須重寫GetHashCode方法?

這允許經由散列工作集合,例如是在一個Dictionary<T, U>鍵,或在HashSet<T>存儲要使用的類型。

當比較類似下面的內容時,使用哪個比較器,Equals或GetHashCode?

GetHashCode不用於比較 - 僅用於散列操作。等於總是被使用。

運算符方法到底做了什麼?它看起來像某種巫術黑魔法在那裏。

這允許您直接在您的類型的兩個實例上使用==。沒有這個,如果你的類型是一個類,你將通過引用來比較,而不是你的類型中的值。

+0

晶瑩剔透,謝謝你分享這個。 :) – 2011-04-09 22:17:42

1

GetHashCode和Equals是兩個完全不同的東西。 Equals確定平等。 GetHashCode返回適合散列映射的散列碼,但不保證相等。因此,在平等問題上,Equals將是決定平等的方法。

GetHashCode用於散列集,例如Dictionary。在字典中查找項目時,您將匹配哈希碼上的條目,然後在Equals上匹配。

3

GetHashCode的目的是爲了平衡哈希表,不是爲了確定平等。在查找散列表的成員時,檢查的散列桶由散列碼確定,然後是否在桶中由相等性確定。這就是GetHashCode必須同意平等的原因。

欲瞭解更多詳情,請參見關於這個問題我的文章:

http://ericlippert.com/2011/02/28/guidelines-and-rules-for-gethashcode/

+0

所以基本上,首先它通過HashCode檢查對象是否存在於集合中,只有在它之後才使用overriden Equals方法實際比較它。它是否正確? – 2011-04-09 22:17:13

+0

你不用使用散列鍵本身來「平衡」散列表,它更多的是這樣做的散列算法。散列函數需要很快,並儘可能少產生衝突(即相同的密鑰)。所以要回答這個問題,平衡=確保元素儘可能均勻分佈在散列表中。 – 2011-04-09 22:19:25

+0

該文章包含一系列規則。類似於'Dictionary '的類假定這些規則是真實的。但是,也有其他地方可能沒有考慮使用'GetHashCode',比如各種LINQ。當你修改'Equals'而不修改'GetHashCode'時,這些規則最終會被破壞,導致依賴這些規則的代碼被破壞。所以,你必須避免任何依賴這些規則的代碼,或者不能同時修改'GetHashCode'來修改'Equals'。一般來說,後一個選項更安全,因爲'GetHashCode'是'object'的成員。 – Brian 2011-04-11 21:18:59

0

的GetHashCode用於通過MSDN 只有當您使用哈希表。

如果你需要平等,你只關心Equals。 MSDN建議也實現GetHashCode,因爲遲早你可能會在對象(哈希表,哈希映射等)中使用你的對象。

想象一下,對象有1000個字節,你需要一個快速的方法來確定2個對象之間的相等性 - 你計算散列鍵(通過GetHashCode)。如果鍵不匹配,則對象不同。如果它們匹配,則不能確定它們是否確實相等,則需要使用Equal()進行驗證 - 這比較昂貴。

哈希表集合使用此ideea。

+1

在某些情況下,即使在非哈希集合中,'GetHashCode'可能對平等測試有用。例如,如果一個不可變的樹類型支持相等比較(如果葉節點持有相同的數據,則它們是相等的,如果它們具有相等的子節點,則其他節點相等),如果節點緩存其「GetHashCode」值,則可以大大加快相等比較,並在比較兒童之前比較哈希碼。如果人們將比較許多幾乎相同的樹,甚至使用一個有5%錯誤匹配的糟糕的'GetHashCode'仍然可以將事情加速近20倍。 – supercat 2012-09-17 16:41:37

相關問題