C#中的類型相等與恒等(Equality & Identity)

來源:互聯網
上載者:User

測試過下面的文章,發現有錯誤,附後面,

CLR提供了可以區分類型的Equality 和Identity能力。

l  Equality:如果兩個對象是相同的類型,並且它們各內建有相同和等值的屬性。(They are instances of the same type and if each of the fields in one object matches the values of the fields in the other object)
Equality必須滿足三個必要條件:reflexive, symmetrics, and transitive
reflexive: 自身相等,及a==a 是永遠成立的;
symmetrics: 對象性,及a==b成立那麼b==a 也成立;
transitive: 傳遞性,及a==b, b==c成立那麼a==c 也成立。

l  Identity:兩個對象必須相等(意味著他們共用同一塊記憶體地區)(The two objects have the same values. – Two objects are identical if they share an address in memory)

CLR提供了至少四種方法來判斷兩個對象的等價性:

1.      Public static bool ReferenceEquals(object left, object right);

2.      Public static bool Equals(object left, object right);

3.      Public virtual bool Equals(object right);

4.      Public static bool operator==(MyClass left, MyClass right);

ReferenceEquals方法總是用來判斷兩個對象的Identity的,不管是針對實值型別還是參考型別。所以針對實值型別,調用該方法總是會返回false,因為實值型別作為這個方法的參數時會進行裝箱操作。

靜態Equals方法提供了判斷兩個對象的Equality能力,在其實現的內部,調用了上述第三個虛擬Equals方法。和ReferenceEquals一樣,它們已經具備從底層判斷兩個對象的能力,我們從來不會覆寫這兩個方法。

執行個體Equals方法也是用來區分兩個對象的Equality的。

l  對於參考型別的對象,它和ReferenceEquals方法幾乎是一樣的。(因為判斷兩個參考型別是否的Equality往往從Identity上就可以區分)

l  而實值型別的對象,我們不僅要判斷他們具有相同的物件類型,還要判斷他們的值相等。實值型別從System.ValueType繼承而來,ValueType已經重寫了Object.Equals()方法,本來已經可以用來滿足這些要求的。但是ValueType.Equals()方法不是很有效,因為它必須要通過反射,在不知道具體的衍生類別型中,完成對它們所含有成員變數的值的比較。因此,建議在我們實現一個實值型別的資料結構時,同時重寫ValueType.Equals()方法。

l  然而我們再回頭看看參考型別,有時兩個參考型別的對象往往被用來進行類似實值型別的比較,比如:String類型,它雖然是參考型別,但它也重寫了Equals方法,因為我們拿它來判斷兩個string是否相同(Equality),實際是希望判斷它們是否具有相同的內容,這是一個value semantics。因此,我們建議在考慮實現一個用作值語義環境下的參考型別時候,也重寫基類的Object.Equals()方法。

註:請參考MDSN或其它相關文檔,如何?Equals方法的重寫。

上面的圖示給了很好的例子來區分Equals和ReferenceEquals方法,被用來做Equility和Identity判斷的區別。

==運算子是可由類重載的運算子,它也是用來判斷恒等的。
對於未重載==的參考型別,會比較兩個參考型別是否引用同一個對象。這跟參考型別的Equals()方法是一樣的。

對於未重載==的實值型別,該運算子會比較這兩個值是否"按位"相等,即是否這兩個值中的每個欄位都相等。和Equals方法一樣,推薦在自訂實值型別中,也要重載==運算子,因為也存在反射在效率上的影響。

==運算子和Equals方法的區別在於多態表現上。Equals方法是重寫,而==運算子是被重載。這意味著除非編譯器知道調用具體的重載版本,否則它只是調用未重載的==版本。

參考資料:
《Essential .NET, Volume 1: The Common Language》 By DonBox, Chris Sells
《Applied Microsoft .NET Framework Programming》By Jeffrey Richter

註:這篇文章第一次發佈於http://chagel.spaces.msn.com 2006/4/30

我的測試代碼:

 

    class  car
    
{
        public string
 f1;
        public int
 f2;
        public
 car()
        
{
        }

    }

    
string first1="hongfeng";//參考型別
            string first2="hongfeng" ;
            int i1=1
;
            int i2=1
;

            car a=new
 car();
            car b=new
 car();
            car c=new
 car();
            car d;

            a.f1="hf"
;
            a.f2=19
;

            b.f1="hongfeng"
;
            b.f2=20
;

            c.f1="hongfeng"
;
            c.f2=20
;

            d=c;//
與c共用一個記憶體區


//            MessageBox.Show(d.Equals(a).ToString());//
false
//            MessageBox.Show(d.Equals(b).ToString());//
false
//            MessageBox.Show(d.Equals(c).ToString());//
false
//            MessageBox.Show(d.Equals(d).ToString());//
true
//            MessageBox.Show(i1.Equals(i1).ToString());//
true
//            MessageBox.Show(i1.Equals(i2).ToString());//
true
//            MessageBox.Show(first1.Equals(first1).ToString());//
true
//            MessageBox.Show(first1.Equals(first2).ToString());//
true

//            MessageBox.Show(Equals(d,a).ToString());//
false判斷對象的Equality
//            MessageBox.Show(Equals(d,b).ToString());//
false
//            MessageBox.Show(Equals(d,c).ToString());//
true
//            MessageBox.Show(Equals(d,d).ToString());//
true
//            MessageBox.Show(Equals(i1,i1).ToString());//
true
//            MessageBox.Show(Equals(i1,i2).ToString());//
true
//            MessageBox.Show(Equals(first1,first2).ToString());//
true
//            MessageBox.Show(Equals(first1,first1).ToString());//
true

//            MessageBox.Show(ReferenceEquals(d,a).ToString());//
false判斷兩個對象的Identity的
//            MessageBox.Show(ReferenceEquals(d,b).ToString());//
false
//            MessageBox.Show(ReferenceEquals(d,c).ToString());//
true
//            MessageBox.Show(ReferenceEquals(d,d).ToString());//
true
//            MessageBox.Show(ReferenceEquals(i1,i1).ToString());//
false實值型別總是返回false
//            MessageBox.Show(ReferenceEquals(i1,i2).ToString());//
false
//            MessageBox.Show(ReferenceEquals(first1,first2).ToString());//
true
//            MessageBox.Show(ReferenceEquals(first1,first1).ToString());//true

看到嗎,其中MessageBox.Show(d.Equals(c).ToString());//false的技術結果為false

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.