C# 對象相等性判斷和同一性判斷


在日常開發中經常需要編寫代碼比較不同的對象。例如,有時需要將對象都放到一個集合中,並編寫代碼對集合中的對象進行排序、搜索或者比較。

System.Object類有兩個Equals方法,如下:

1、實例Equals方法(可重寫),代碼如下:

public virtual bool equals(object obj) => RuntimeHelpers.Equals(this, obj)

再看看RuntimeHelpers.Equlas里面調的是什么方法,代碼如下:

[MethodImpl(MethodImplOptions.InternalCall), SecuritySafeCritical]
public static extern bool Equals(object o1, object o2);

ok,這里的extern關鍵字告訴你,接下來的不用你考慮了!

2、靜態方法Equals方法,代碼如下:

public static bool Equals(object objA,object objB)=>
((objA==objB) || (((objA!=null) && (objB!=null)) &&  objA.Equals(objB)))

繼續深入解析代碼,發現objA.Equals調用了上面的實例Equals方法.其實就是在實例Equals方法的基礎上做了非空判斷.然后方法做了靜態化.

到這里源碼解析完畢,由於到extern這一步解析不下去了(博主實力有限),如有知道的請告知!萬分感謝!

 

由於類型能夠重寫Equals方法,所以Equals方法的邏輯遠比想象的要復雜.下面來舉幾個例子:

1、由於類型能夠重寫Equals方法,所以不能使用它來測試同一性,為了解決這個問題,Object類型提供了ReferenceEquals方法來比較兩個對象的同一性,ReferenceEquals代碼如下:

public static bool ReferenceEquals(object objA,object objB)=>(objA==objB)

注:判斷兩個對象的"同一性"不應該使用C#的==操作符(除非將兩個操作符進行裝箱轉換為Object),因為某個操作數可能重載了==操作符

 

2、System.ValueType(所有值類型的基類)就重寫了Object的Equals方法,並對兩個對象進行了正確的值相等檢查而不是同一性檢查.代碼如下:

public bool Equals(uint obj)=>(this == obj);

==操作符進行的值檢查.

ValueType.Equals內部會進行一下操作:

1、如果obj實參為null,就返回false;

2、如果this和obj引用的是不同的對象,返回false;

3、針對類型定義的每個實例字段,都將this對象中的值與obj對象中的值進行比較(通過調用對象的Equals方法)。任何字段不相等,就返回false.

4、返回true,ValueType的Equals方法不掉用Object的Equals方法.

上述3步驟,是通過反射實現,由於CLR的反射機制效率不高,所以在定義自己的值類型的時候,應重寫Equals方法來提供自己的實現,從而提高自己類型進行值類型比較時的性能.注:自己的實現不用調用base.Equals().

當我們定義自己的類型時,重寫的Equals方法要符合下面幾個特性:

1、Equals必須自反 x.Equals(x)肯定返回true.

2、Equlas必須對稱 x.Equals(y)和y.Equals(x)必須返回相同的值

3、Equals必須可傳遞 x.Equals(y)返回true,y.Equals(z)返回true則x.Equals(z)也必須返回true.

4、Equals必須一致,比較的兩個值不變,Equals返回值(true或false)也不能變

如果實現的Equals方法不符合上述特性,應用程序就會行為失常.

 

重寫Equals方法必須做以下幾件事

1、讓類型實現System.IEquatable<T>接口的Equals方法

這個泛型接口允許定義類型安全的Equals方法,通常實現的Equals方法應獲取一個Object參數,以便在內部調用類型安全的Equals方法.

2、重載==和!=操作符方法

通常應實現這些操作符方法,在內部調用類型安全的Equals方法.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM