2010-12-12 127 views
10

你在編寫對你創建的structsclasses進行相等性檢查的方法是什麼?C#平等檢查

1)是否 「完全」 平等檢查需要大量的樣板代碼(如override Equalsoverride GetHashCode,通用Equalsoperator==operator!=)?

2)您是否明確指定您的類將模擬IEquatable<T>接口?

3)我是否理解正確的話,那還有自動應用Equals覆蓋沒有實際的辦法,當調用類似a == b,我總是要同時實現Equalsoperator==成員?

回答

20

你說得對,這是一個很大的鍋爐板代碼,你需要單獨實現的一切。

我會推薦:

  • 如果你要實現價值平等可言,覆蓋GetHashCodeEquals(object) - 用於創建==超載和實施IEquatable<T>沒有做,可能會導致非常意外的行爲
  • 我會始終貫徹IEquatable<T>如果你覆蓋Equals(object)GetHashCode
  • 我只有正確重載==操作符更很少
  • 實現平等啓封類是棘手的,而且還可以產生令人驚訝的/不希望的結果。如果您需要層次結構中的類型相等,請執行IEqualityComparer<T>表示您感興趣的比較。
  • 可變類型的平等通常是一個壞主意,因爲兩個對象可以相等,然後不等。如果一個對象在用作哈希表中的關鍵字後發生了變化(以影響等式的方式),您將無法再次找到它。
  • 一些鍋爐板的結構略有不同...但像馬克,我很少寫自己的結構。

這裏是一個示例實現:

using System; 

public sealed class Foo : IEquatable<Foo> 
{ 
    private readonly string name; 
    public string Name { get { return name; } } 

    private readonly int value; 
    public int Value { get { return value; } } 

    public Foo(string name, int value) 
    { 
     this.name = name; 
     this.value = value; 
    } 

    public override bool Equals(object other) 
    { 
     return Equals(other as Foo); 
    } 

    public override int GetHashCode() 
    { 
     int hash = 17; 
     hash = hash * 31 + (name == null ? 0 : name.GetHashCode()); 
     hash = hash * 31 + value; 
     return hash; 
    } 

    public bool Equals(Foo other) 
    { 
     if ((object) other == null) 
     { 
      return false; 
     } 
     return name == other.name && value == other.value; 
    } 

    public static bool operator ==(Foo left, Foo right) 
    { 
     return object.Equals(left, right); 
    } 

    public static bool operator !=(Foo left, Foo right) 
    { 
     return !(left == right); 
    } 
} 

是的,這是一個很大的樣板赫克,這很少的實現:(

==實施是稍微之間變化效率比它可能低,因爲它會通過呼籲Equals(object)哪些需要做動態類型檢查...但替代是更多的鍋爐板,如下所示:

public static bool operator ==(Foo left, Foo right) 
{ 
    if ((object) left == (object) right) 
    { 
     return true; 
    } 

    // "right" being null is covered in left.Equals(right) 
    if ((object) left == null) 
    { 
     return false; 
    } 
    return left.Equals(right); 
} 
+1

^^你的每個職位是一個C#學習章節.. :) – Dienekes 2010-12-14 10:08:15

+0

對於第二個代碼塊的2個小建議:1)你不應該把==(對象)從== =='移動到通用'Equals'嗎?因此,即使對於通用的「Equals」方法,速度(當然這取決於,但假設最壞的情況)會檢查引用相等性嗎? 2)你不需要在'=='中進行第二次空的檢查'(對象)right == null',因爲你基本上是在泛型'Equals'中做的。看到我的帖子.. – nawfal 2012-12-16 20:53:24

+0

@nawfal:我認爲在通用的'Equals'情況下做這件事並沒有多大意義 - 無論如何,在* *爲true的情況下它會很快,對於它的情況*不是真的,它增加了一個額外的檢查沒有任何好處。至於零部分 - 這將需要再次檢查動態類型。是的,你可以爲兩者爭辯 - 但我很滿意我兩年前寫的東西...... – 2012-12-16 20:58:04

1

你只需要實現== == b的運算符==。
因爲我喜歡我的數據在字典有時我重寫GetHashCode。
接下來我實現了Equals(作爲未提及的標準......這是因爲在使用泛型時沒有對平等的限制)並指定實現IEquatable。由於我要這樣做,所以我不妨將我的==和!=實現指向Equals。 :)

6

我很少做任何特別的課程;對於大多數常規對象而言,引用平等很好。我很少寫一個struct;但由於結構代表的值通常提供平等等是合適的。這通常涉及一切;等於,==,!=和IEquatable<T>(因爲這使用EqualityComparer<T>.Default避免場景拳擊。

樣板通常不是問題太多,但IIRC工具,如ReSharper的幫助在這裏。

是的,這是明智的保持Equals和==同步,而這需要明確地完成。