標籤:
對象相等性和同一性
- System.Object 類型提供了以下方法,
1 namespace System 2 { 3 // 4 // 摘要: 5 // 支援 .NET Framework 類階層中的所有類,並為衍生類別提供低層級服務。這是 .NET Framework 中所有類的最終基類;它是類型階層的根。 6 [ClassInterface(ClassInterfaceType.AutoDual)] 7 [ComVisible(true)] 8 public class Object 9 {10 //11 // 摘要:12 // 初始化 System.Object 類的新執行個體。13 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]14 public Object();15 16 //17 // 摘要:18 // 允許對象在“記憶體回收”回收之前嘗試釋放資源並執行其他清理操作。19 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]20 ~Object();21 22 //23 // 摘要:24 // 確定指定的對象執行個體是否被視為相等。25 //26 // 參數:27 // objA:28 // 要比較的第一個對象。29 //30 // objB:31 // 要比較的第二個對象。32 //33 // 返回結果:34 // 如果認為對象相等,則為 true;否則為 false。如果 objA 和 objB 都為 null,則方法返回 true。35 [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]36 public static bool Equals(Object objA, Object objB);37 //38 // 摘要:39 // 確定指定的 System.Object 執行個體是否是相同的執行個體。40 //41 // 參數:42 // objA:43 // 要比較的第一個對象。44 //45 // objB:46 // 要比較的第二個對象。47 //48 // 返回結果:49 // 如果 objA 是與 objB 相同的執行個體,或如果兩者均為 null,則為 true;否則,為 false。50 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]51 [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]52 public static bool ReferenceEquals(Object objA, Object objB);53 //54 // 摘要:55 // 確定指定的對象是否等於當前對象。56 //57 // 參數:58 // obj:59 // 要與當前對象進行比較的對象。60 //61 // 返回結果:62 // 如果指定的對象等於當前對象,則為 true;否則為 false。63 [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]64 public virtual bool Equals(Object obj);65 //66 // 摘要:67 // 作為預設雜湊函數。68 //69 // 返回結果:70 // 當前對象的雜湊碼。71 [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]72 public virtual int GetHashCode();73 //74 // 摘要:75 // 擷取當前執行個體的 System.Type。76 //77 // 返回結果:78 // 當前執行個體的準確運行時類型。79 [SecuritySafeCritical]80 public Type GetType();81 //82 // 摘要:83 // 返回表示當前對象的字串。84 //85 // 返回結果:86 // 表示當前對象的字串。87 public virtual string ToString();88 //89 // 摘要:90 // 建立當前 System.Object 的淺表副本。91 //92 // 返回結果:93 // 當前 System.Object 的淺表副本。94 [SecuritySafeCritical]95 protected Object MemberwiseClone();96 }97 }Syste.Object
- 其中提供了名為Equals的虛方法,它的作用是在兩個對象相等的前提下返回true.
- Equals方法初實現
看起來似乎是合理的實現,但問題是如果實參引用不同的對象,Equals就不能判斷對象是否包含相同的值,就會判定為False.對於Object的Equals的預設實現,它實現的是同一性,而非相等性。
- 針對以下問題,1)obj實參是否為null,2)this和obj實參是否是引用同一個對象,3)this和obj實參是否引用不同類型的對象,實現Object的Equals方法。
1 public class Object 2 { 3 public virtual Boolean Equals(Object obj) 4 { 5 if (obj == null) 6 return false; 7 if (this.GetType() != obj.GetType()) 8 return false; 9 10 return true; ;11 }12 }Equals方法
- 一個類型重寫Equals方法時,重寫的方法應調用基類的Equals實現(除非這個基類就是Object).另外一個類型能重寫Object的Equals方法,所以不能在調用這個Equals方法來測試同一性。Object提供了一個靜態方法ReferenceEquals,其原型如下:
1 public Boolean ReferenceEquals(Object objA, Object objB)2 {3 return (objA == objB);4 }ReferenceEquals如果想檢查同一性(看兩個引用是否指向同一個對象),那麼務必調用ReferenceEquals,而不應使用C#的==操作符(除非先把兩個運算元都轉型為Object)
- ValueType的Equals方法使用反射技術,由於CLR的反射機制較慢,所以在定義自己的實值型別時,應該重寫Equals方法,提供自己的實現,以便在用類型的執行個體進行值的相等性比較時提高效能。當然,在自己的視線中,不要調用base.Equals。
- 定義自己的類型時,如果決定重寫Equals,必須確定它符合相等性的4個特徵。
- 1)Equals必須是自反的。
- 2)Equals必須是對稱的。
- 3)Equals必須是可傳遞的。
- 4)Equals必須是一致的。
- 重寫Equals方法,還要:
- 讓類型實現System.IEquatable<T>介面的Equals方法。這個泛型介面允許你定義一個型別安全的Equals方法。
- 重載==和!=操作符方法 通常應事先這些操作符方法,在內部調用型別安全的Equals方法.
除此之外,假如以後出於排序的目的而比較類型的執行個體,那麼類型華英實現System.IComparable的CompareTo方法和System.IComparable<T>的CompareTo方法。
對象雜湊嗎
System.Object提供了虛方法GetHashCode,它能擷取任意對象的Int32雜湊嗎。
- 如果定義的一個類型重寫了Equals方法,那麼還應重寫GetHashCode()方法。如果定義的類型在重寫Equals的同時沒有重寫GetHashCode(),Microsoft的C#編譯器會報告一條警告訊息,例如以下類型,會顯示警告訊息:warning CS0659:“Program”重寫Object.Equals(object o)但不重寫Object.HetHashCode().
- 重寫Equals
之所以要同時定義GetHashCode,是因為在System.Collections.Hashtable類型、System.Collections.Generic.Dictionary類型以及其他一些集合的實現中,要求兩個對象為了相等,必須具有相同的雜湊嗎,所以,如果重寫了Equals,那麼還應重寫GetHashCode,確保相等性演算法和對象雜湊嗎演算法是一致的。
1 internal sealed class Point2 {3 private Int32 m_x, m_y;4 public override int GetHashCode()5 {6 return m_x ^ m_y;7 }8 }GetHashCode
關於 warning CS0659:“***”重寫Object.Equals(object o)但不重寫Object.GetHashCode()