C#筆記 – 對象相等性和同一性Reading Notes, C#, Developing / By LoneliNerd / 2023 年 5 月 26 日 2023 年 6 月 14 日 對象相等性和同一性System.Object提供了Equals虛方法,其實現為:public class Object{ public virtual bool Equals(Object obj) { if(this == obj) { return true; } return false; }}該實現只是判斷「對象」是否與自身包含一樣的值,是「同一性」,而不是「相等性」另外,由於類型能重寫Object的Equals方法,因此不能再通過Equals來測試同一性;同理 == 操作符也能被重載。因此想要安全地測試同一性,應使用ReferenceEquals正確的相等性實現應該包含:參數對象空判斷自身對象與參數對象的引用同一性自身對象與參數對象中的每個實例字段的值比較調用基類的Equals方法public class Object{ public virtual bool Equals(Object obj) { if(obj == null) { return false; } if(this.GetType() != obj.GetType()) { return false; } return true; }}實際上,System.ValueType就進行了正確的相等性測試實現判斷對象是否為空判斷引用對象類型是否一致利用反射,對this對象和obj對象中的所有值進行比較CLR的反射機制慢,因此自定義值類型時應重寫Equals方法,而Equals方法應符合相等性的4個特徵:自反:x.Equals(x)必然為true對稱:x.Equals(y) = y.Equals{x}可傳遞:x.Equals(y) = true; y.Equals(z) = true; then x.Equals(z) = true一致:比較的兩個值不變,其返回值也不變另外,可以通過實現IEquatable接口或重載==和!=操作符來確保內部調用類型安全的Equals方法對象哈希碼System.GetHashCode獲取任意對象的int32哈希碼如果重寫了Equals,那就必須重寫GetHashCode因為在一些集合(如Dictionary)的實現中,要求兩個對象必須具有相同的HashCode才被視為相等,所以重寫Equals就必須重寫GetHashCode。向集合添加KeyValuePair時,首先要獲取鍵對象的HashCode。該HashCode指出鍵值對要存儲到哪個bucket中。查找Key時,會獲取指定Key對象的HashCode。該HashCode標識要搜索的bucket,然後在bucket中查找與指定Key對象相等的Key對象因此,一旦修改了集合中的一個Key對象,集合就再也找不到該對象所以,需要修改HashTable中的Key對象時,應先移除原來的KeyValuePair,修改,再把改完的加回去哈希碼算法規則:提供良好隨機分布不要調用Object/ValueType的GetHashCode至少使用一個實例字段算法使用的字段應該是在生存期不可變的夠快包含相同值的不同對象應返回相同的HashCode 參考書目《CLR via C#》(第4版) Jeffrey Richter《深入理解C#》(第3版) Jon Skeet