2010-04-29 36 views
114

我希望我的Food類能夠測試何時它等於另一個實例Food。稍後我將使用它來對付List,並且我想使用它的List.Contains()方法。我應該執行IEquatable<Food>還是隻覆蓋Object.Equals()?從MSDN:IEquatable和剛剛重寫Object.Equals()之間有什麼區別?

此方法,使用默認的相等比較, 如由對象的 實現對於T (值的列表中的類型)的 IEquatable.Equals方法的定義由 確定平等。

所以我的下一個問題是:.NET框架的哪些函數/類使用Object.Equals()?我應該首先使用它嗎?

+2

這裏很好的解釋http://blogs.msdn.com/b/jaredpar/archive/2009/01/15/if-you-implement-iequatable-t-you-still-must-override-object- s-equals-and-gethashcode.aspx – nawfal 2013-04-14 12:13:49

+1

@nawfal:在接受的答案中已經提到過。 – 2013-04-14 16:50:12

+0

[Understanding IEquatable](http://stackoverflow.com/questions/411500/understanding-iequatable)可能的重複 – nawfal 2013-10-08 05:19:23

回答

140

主要原因是表現。當在.NET 2.0中引入泛型時,他們能夠添加一堆整齊的類,如List<T>,Dictionary<K,V>,HashSet<T>等。這些結構大量使用GetHashCodeEquals。但對於價值類型,這需要拳擊。 IEquatable<T>讓一個結構實現強類型Equals方法,因此不需要裝箱。因此,在使用泛型集合的值類型時性能會好得多。

參考類型沒有太多好處,但IEquatable<T>實現允許您避免來自System.Object的強制轉換,如果頻繁調用它可能會產生影響。

雖然在Jared Parson's blog上指出,但你仍然必須實現Object overrides。

+0

引用類型之間是否存在任何轉換?我一直認爲,當你將一些不明顯的對象從一種對象分配給另一種對象時,對於編譯器來說,強制轉換隻是「聲明」。在編譯之後,代碼甚至不知道那裏是否有投射。 – 2010-04-29 05:41:50

+5

這在C++中是正確的,但不是強制類型安全的.NET語言。有一個運行時間轉換,如果轉換不成功,則拋出異常。所以在鑄造時需要花費很少的運行時間。編譯器可以優化掉upcasts例如object o =(object)「string」;但是向下轉換 - string s =(string)o; - 必須在運行時發生。 – Josh 2010-04-29 05:58:53

+1

我明白了。偶然的情況下,你有什麼地方可以獲得關於.NET的那種「更深入」的信息?謝謝! – 2010-04-29 06:03:39

34

按照MSDN:的 Object.Equals(Object)GetHashCode 使他們的行爲是一致的 與該IEquatable(T).Equals 方法

如果實現IEquatable(T),你 也應該覆蓋基類 實現。如果您確實覆蓋了 Object.Equals(Object),那麼您的類的靜態Equals(System.Object, System.Object)方法中的調用 也會調用您的重寫的 實現。 這確保所有調用 的Equals方法返回一致的 結果。

因此,似乎兩者之間沒有真正的功能差異,除非可以根據類的使用方式來調用。從性能角度來看,它更好地使用通用版本,因爲不存在與其相關的裝箱/拆箱處罰。

從邏輯的角度來看,實現接口也更好。重寫對象並不能真正告訴任何人你的類實際上是可以相等的。重寫可能只是一個無所事事的類或淺層實現。明確地使用接口說:「嘿,這個東西適用於平等檢查!」這只是更好的設計。

+0

是的,他們都是好點。 – 2010-04-29 05:42:22

+4

如果結構體將用作Dictionary或類似集合中的鍵,那麼它肯定應該實現iEquatable(ofOwnType);它將提供重大的性能提升。通過實現IEquatable(的OwnType),非繼承類將獲得輕微的性能提升。可繼承的類應該// //不實現IEquatable。 – supercat 2010-12-07 16:34:31

19

擴展Josh說的一個實際例子。+1給Josh - 我正要在我的回答中寫下同樣的內容。

public abstract class EntityBase : IEquatable<EntityBase> 
{ 
    public EntityBase() { } 

    #region IEquatable<EntityBase> Members 

    public bool Equals(EntityBase other) 
    { 
     //Generic implementation of equality using reflection on derived class instance. 
     return true; 
    } 

    public override bool Equals(object obj) 
    { 
     return this.Equals(obj as EntityBase); 
    } 

    #endregion 
} 

public class Author : EntityBase 
{ 
    public Author() { } 
} 

public class Book : EntityBase 
{ 
    public Book() { } 
} 

這樣一來,我已經重新使用equals()方法是比較適合我的所有派生類的盒子的方法。

+0

還有一個問題。使用「obj作爲EntityBase」而不是(EntityBase)obj有什麼優勢?只是一個風格問題,或者有什麼優勢?在「obj爲EntityBase」的情況下爲 – 2010-04-29 05:44:49

+15

- 如果obj不是EntityBase類型,它將傳遞「null」並繼續而沒有任何錯誤或異常,但是在「(EntityBase)obj」的情況下,它會強制嘗試obj到EntityBase,如果obj不是EntityBase類型,則會拋出InvalidCastException。是的,「as」只能應用於參考類型。 – 2010-04-29 06:05:16

+0

啊,我明白了。大。謝謝! – 2010-04-29 06:08:31

相關問題