2011-06-24 57 views
21

我覆蓋了我的類的Equals()以比較類型爲Guid的ID值。警告:「...覆蓋Object.Equals(對象o),但不覆蓋Object.GetHashCode()」

然後Visual Studio中警告說:

...重寫Object.Equals(對象o),但 不重寫Object.GetHashCode()

所以我隨後也推翻它的GetHashCode( )像這樣:

public partial class SomeClass 
{ 
    public override bool Equals(Object obj) 
    { 
     //Check for null and compare run-time types. 
     if (obj == null || this.GetType() != obj.GetType()) return false; 

     return this.Id == ((SomeClass)obj).Id; 
    } 

    public override int GetHashCode() 
    { 
     return this.Id.GetHashCode(); 
    } 
} 

它似乎工作。 我做得對嗎?記得Id是Guid類型的。 我的課是一個實體框架對象嗎?

回答

6

既然你不是在處理一個封閉的類,我建議不要檢查類的平等,就像這樣。所有子類的SomeClass應該能夠參加Equals也,所以你可能要改爲使用:

if (obj as SomeClass == null) return false; 
+0

什麼時候子類實例會等於基類實例?該子類將具有其他屬性,並且基類在執行比較時不會了解它們。 –

+3

'Equals'目前僅用於處理所有子類將擁有的'Id'。 – recursive

+0

我承認你的邏輯,但正如我在對Eric的評論中指出的,OP的Equals代碼直接來自[官方MSDN文檔]示例(http://msdn.microsoft.com/en-us/庫/ bsc2ak47(v = vs.110)的.aspx)。 (請參閱Point類示例)。 – kmote

5

傳統Equals以這樣的方式,兩個對象只會是「平等」,如果他們實施在各方面都完全一樣。例如,如果您有兩個對象表示數據庫中的同一對象,但其中一個對象的屬性不同於另一對象,則這些對象不會被視爲「等於」,並且應該避免在可能的情況下生成相同的「哈希碼」 。

在「不等於」一邊比錯誤地調用兩個不相等的對象更好。這就是爲什麼對象的默認實現使用對象本身的內存位置:沒有兩個對象永遠不會被視爲「相等」,除非它們是完全相同的對象。所以我會說,除非你想寫GetHashCodeEquals這樣一種方式來檢查它們所有屬性的相等性,你最好不要覆蓋任何一種方法。

如果您有一個數據結構(如HashSet),您特別想根據ID值確定相等性,則可以爲該數據結構提供一個特定的IEqualityComparer實現。

8

它看起來對我很正確。每當我做這樣的事情時,我通常也執行IEquatable,以便在相同編譯時類型的變量之間進行比較會更有效一些。

public partial class SomeClass : IEquatable<SomeClass> 
{ 
    public override bool Equals(Object obj) 
    { 
     return Equals(obj as SomeClass); 
    } 
    public bool Equals(SomeClass obj) 
    { 
     if (obj == null) 
      return false; 
     return Id == obj.Id; 
    } 
    public override int GetHashCode() 
    { 
     return Id.GetHashCode(); 
    } 
} 

該結構還允許將具有相同Id的更多派生對象比較爲等於派生更少的對象。如果這不是所需的行爲,那麼您將不得不按照問題中的類型進行比較。

if (obj.GetType() != typeof(SomeClass)) return false; 
29

正如其他人所說的那樣,在Equals中使用Reflection似乎不太合適。除此之外,讓我們專注於GetHashCode。

GetHashCode的主要規則,你不能違反如果兩個對象相等,那麼它們必須具有相同的散列碼。或者,如果兩個對象具有不同的哈希代碼,則它們的等同方式是,那麼它們必須不相等。你的實現在那裏看起來不錯。

您可以自由違反反面意見。也就是說,如果兩個對象具有相同的散列碼,那麼它們被允許相等或不相等,正如您認爲合適的那樣。

我假設「Id」是一個不變的屬性。如果「Id」可以在對象的生命週期內改變,那麼當把對象放在哈希表中時可能會遇到問題。考慮確保只有不可變屬性用於計算相等和散列碼。

你的實現看起來不錯,但是你問這個問題的事實表明你可能沒有牢牢掌握構建GetHashCode實現的所有細微因素。一個良好的開始是我的主題文章:

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

+0

我已閱讀您的文章,並同意您的觀點,但我發現自己處於一種只有可變屬性的「DataContract」的情況。 '公共字符串日{get;組; ''例如。似乎.NET的自動序列化需要屬性是可變的。我的'Equals'方法應根據這些可變屬性確定兩個對象是否相等。不存在不可變屬性。因此,我無法生成安全的'GetHashCode'方法。看起來我的選擇是不重寫'Equals',或者永遠不要將我的'DataContract'放到一個哈希表中...... – crush

+0

@crush:你有第三個選項,它是*當它處於哈希表*。 –

+1

我在你的文章中讀到過,但似乎很難確保合同不被破壞。 – crush

4

你得外觀極好回答您的第一個問題:

我有沒有做正確嗎?

我會回答你的第二個問題

會有問題,我的班是一個實體框架的對象?

是的,它很重要。實體框架在內部使用HashSet。例如,動態代理使用HashSet來代表集合導航屬性,並且EntityObject使用EntityCollection,其在內部依次使用HashSet

+1

+1:因此,除非您瞭解實體框架如何期待它們的行爲,否則不要混淆哈希代碼。 – StriplingWarrior

+0

我想知道OP實現是否需要根據您的答案進行修改..您說它很重要,爲什麼它很重要,但不是這意味着實現GetHashCode()的實現者。你能提供更多的信息嗎? – Andrew

+0

@Andrew:該信息是在其他答案。 OP的實施不需要任何改變。 –