C#(.NET)的object類裏面有三個關於判斷相等性的方法:安全
還有一個接口:IEquatable<T>也能夠用來判斷相等性。性能
比較這個Class的兩個實例,它們的屬性值是同樣的:3d
輸出結果:blog
之因此結果是False,是由於object.Equals()評估的是引用的相等性,除非進行了重寫。繼承
這是兩個字符串,並且使用string.Copy()能夠保證它們不指向同一個地址(若是不使用string.Copy(),而直接賦兩個一樣的值,那麼可能會發生字符串駐留問題:https://www.cnblogs.com/artech/archive/2007/03/04/663728.aspx):接口
這時輸出的結果是:字符串
可是咱們看一下string這個類,能夠發現string有不少Equals()方法:get
若是按照上面這麼寫的話,它並無調用object.Equals()方法。因此咱們改一下代碼:源碼
這時調用的是object.Equals()方法,它的輸出依然是:string
這是由於string類對object的Equals()方法進行了重寫,重寫後比較的是字符串的值。
除了string以外,delegates和Tuples也對object.Equals()方法進行了重寫。不過對大部分的.NET類型來講,object.Equals()比較的是引用。
值類型是存放在Stack上面的,它們一般沒有引用,除非你對它們進行裝箱操做。
那麼對值類型使用object.Equals()方法,應該沒有什麼意義。。。
有這麼一個自定義的Struct:
而後進行兩組比較:
輸出結果是:
很顯然,結果有點出乎個人意料,針對這個Struct類型,object.Equals()比較的是它們的值。
這是由於全部的struct都繼承於System.ValueType,而System.ValueType繼承於System.Object,System.ValueType它對object.Equals()方法進行了重寫,重寫的方法裏會比較值類型裏面全部的字段(Field),若是全部字段都相等,那麼就返回true。
可是System.ValueType的重寫是使用反射來找到全部的字段(Fields),因此性能比較差。
因此針對值類型最好的辦法是本身重寫一下Equals()方法。
默認狀況下,針對引用類型,object.Equals()比較的是引用;針對值類型,object.Equals()比較的是值。
可是全部的類型均可以重寫object.Equals()方法,例如string。
使用object virtual的Equals()方法能夠應付大部分狀況,可是若是該引用是null,那麼使用該方法就會報錯了:
這時候咱們就可使用object類的靜態Equals()方法:
(也能夠不寫object)
而結果固然是:
結果是:
在.NET/.NET Core 裏面,null和null是相等的。
靜態Equals()方法的源碼其實很簡單,除了檢查null以外,它會給出和virtual Equals()方法一樣的結果。
若是你對virtual的Equals()方法進行了重寫,而因爲靜態的Equals()方法就會調用重寫的virtual Equals()方法,因此這兩個方法要保持一向性。
它和前兩種方法有點像,可是也不盡相同。
雖然virtual和靜態的Equals()方法一般會比較引用,可是virutal的方法能夠被重寫,從而比較的是值,例如string。因此使用ReferenceEquals()來比較兩個變量是否指向同一個實例是更安全準確的。
看下面這兩個比較:
第一個比較調用的是object的virtual Equals()方法,可是string對其進行了重寫,比較的是值:
而第二個比較是object的靜態的ReferenceEquals()方法,因爲是靜態的,因此無法重寫:
而C#裏的==是什麼原理,之後再說。
System.Object的static bool Equals(object obj)這個方法,由於其參數是object類型,因此它能夠對任何引用類型進行比較。可是若是想比較值類型的話,那麼值類型就會被裝箱,而後再進行比較。可是裝箱的動做會有性能損耗,而之因此採用值類型的主要緣由就是由於性能。因此這是一個問題。
再者,使用該方法來比較兩個不相干的類型,好比Apple和Book這兩個Class,比較的時候不會報錯,可是這沒有任何意義。這就是由於參數不是強類型,纔會出現這些問題。
而IEquatable<T>這個接口就能夠解決這些問題。
它只定義了一個方法:bool Equals(T other)。
例子,三個int:
使用它的Equals()方法:
能夠看到除了object.Equals(object obj)這個方法外,它還有一個Equals(int obj)這個方法,它的參數是強類型的,這是由於int實現了IEquatable<T>接口。
而其源碼大體以下:
因此平時比較int的時候使用==便可。
全部的原始類型都實現了IEquatable<T>接口。int, byte...
而IEquatable<T>對值類型很是有用。
可是對引用類型沒有太大的用處,由於引用類型比較時不存在裝箱問題,並且IEquatable<T>在繼承方面仍是存在問題的,可是string仍是實現了IEquatable<T>接口,由於string是seal的,不存在繼承。
須要注意的是若是實現了IEquatable<T>,那麼它的實現方法和重寫的object.Equals()方法應該保持一致,作一樣的事。