首頁 > 後端開發 > C#.Net教程 > 一次搞懂C#中的==、Equals()和ReferenceEquals()的差別

一次搞懂C#中的==、Equals()和ReferenceEquals()的差別

高洛峰
發布: 2016-12-16 09:45:15
原創
1759 人瀏覽過

首先看CLR中基本值型別之間的比較,先看程式碼:

            int age1 = 30;            int age2 = 30;

            Console.WriteLine("int == int: {0}", age1 == age2);
            Console.WriteLine("int == int: {0}", age2 == age1);
            Console.WriteLine("int Equals int: {0}", age1.Equals(age2));
            Console.WriteLine("int Equals int: {0}", age2.Equals(age1));
            Console.WriteLine("int ReferenceEquals int: {0}", object.ReferenceEquals(age1, age2));
            Console.WriteLine("int ReferenceEquals int: {0}", object.ReferenceEquals(age2, age1));

            Console.ReadLine();
登入後複製

運行結果:

一次搞懂C#中的==、Equals()和ReferenceEquals()的差別

對於相同的基本值型別(上述範例程式碼中都是int),==和Equals()比較結果是一樣的;由於ReferenceEquals()是判斷兩個物件的參考是否相等,對於值類型,因為每次判斷前都必須進行裝箱操作,也就是每次都產生了一個臨時的object,因而永遠返回false。下面我把程式碼裡面的age2的型別改為byte型,比較結果有什麼變化呢?請看運行結果:

一次搞懂C#中的==、Equals()和ReferenceEquals()的差別

現在我們發現,age1.Equals(age2)和age2.Equals(age1)結果不一樣。在基本值型別的比較中,==比較的是"值"的內容,如果兩個物件的"值"一樣,則兩個物件是"=="的;但是Equals()做的事要稍微多一點,在Equal()中其實還存在著一個"隱式轉換"的過程,也就是說上面程式碼中的age1.Equals(age2)相當於int.Equals(int),byte型資料可以隱式轉換為int型數據,所以age1.Equals(age2)結果為true;而age2.Equals(age1)相當於byte.Equals(byte),但int型資料不能隱式轉成byte型,因為存在資料精確度遺失的可能。其實,age2.Equals(age1)的Equals()應該類似與下面的程式碼:

        public override bool Equals(object obj)
        {            if (!(obj is Byte))
            {                return false;
            }            return m_value == ((Byte)obj).m_value;
        }
登入後複製

如果是明確轉換,age2.Equals((byte)age1)這個時候結果就是true了。

下面說一下字串string類型之間的比較,字串是特殊的引用類型,因為它是"不可變"的。先看程式碼:

            string name1 = "Jack";            string name2 = "Jack";            object o1 = name1;            object o2 = name2;

            Console.WriteLine("name1 == name2: {0}", name1 == name2);
            Console.WriteLine("name1 Equals name2: {0}", name1.Equals(name2));

            Console.WriteLine("o1 == o2: {0}", o1 == o2);
            Console.WriteLine("o1 Equals o2: {0}", o1.Equals(o2));

            Console.WriteLine("o1 == name2: {0}", o1 == name2);
            Console.WriteLine("o1 Equals name2: {0}", o1.Equals(name2));

            Console.WriteLine("name1 ReferenceEquals name2: {0}", object.ReferenceEquals(name1, name2));
            Console.WriteLine("o1 ReferenceEquals o2: {0}", object.ReferenceEquals(o1, o2));

            Console.ReadLine();
登入後複製

上述程式碼運行結果:

一次搞懂C#中的==、Equals()和ReferenceEquals()的差別

比較結果全部都是true,現在逐一解釋。有人會說name1和name2儲存的都是"Jack",所以name1和name2其實就是同一個對象,所以name1==name2和name1.Equals(name2)的比較結果是一樣的;也許你是對的。我們透過.NET Reflector工具查看string的原始碼,會看到其中的這一段程式碼:

一次搞懂C#中的==、Equals()和ReferenceEquals()的差別

運算元==其實就是回傳了Equals()而已。所以對於為什麼name1==name2和name1.Equals(name2)的比較結果是一樣的解釋,我覺得這個解釋比"name1和name2其實就是同一個對象"說法更直觀一些。

我們知道,由於string類型的特殊性,CLR可以透過一個string物件共享多個完全一致的string內容,所以上面的name1和name2指向的地方是一樣的,下面的o1 == o2、o1 == name2、object.ReferenceEquals(name1, name2)的比較結果都是true也驗證了這個說法(其實object.ReferenceEquals(name1, o2)也是true)。但是,如果把name1和name2的賦值變成這樣呢?

            string name1 = new string(new char[] { 'J', 'a', 'c', 'k' });
            string name2 = new string(new char[] { 'J', 'a', 'c', 'k' });
登入後複製

看運行結果:

一次搞懂C#中的==、Equals()和ReferenceEquals()的差別

name1==name2和name1.Equals(name2)的比較結果一樣好理解,就像上面說的,操作符==其實就是回傳了Equals()(而已引用型,Equals()比較的都是託管堆上儲存的內容),所以二者結果一樣。但是object物件o1和o2的比較,o1 == o2和o1.Equals(o2)結果不一樣了。 object物件的==比較的是型別物件指針,o1和o2是兩個object,二者的型別物件指針必然不同;Equals()比較的是o1和o2在託管堆上儲存的內容,故o1.Equals (o2)為true。這也說明了下面的o1 == name2為false和o1.Equals(name2)為true了。

我們先看一下object.ReferenceEquals內部的程式碼:

一次搞懂C#中的==、Equals()和ReferenceEquals()的差別

現在對於object.ReferenceEquals(name1, name2)和object.ReferenceEquals(o1, o2)結果都是理解了,其實應該很不錯個object的==問題!

最後說一下自訂引用類型的比較。

    class MyName
    {
        private string _id;
        public string Id
        {
            get { return _id; }
            set { _id = value; }
        }

        public MyName(string id)
        {
            this.Id = id;
        }
    }
登入後複製

把上面name1和name2的聲明改為:

            MyName name1 = new MyName("12");
            MyName name2 = new MyName("12");
登入後複製

其他不變,運行結果:

一次搞懂C#中的==、Equals()和ReferenceEquals()的差別

name1和name2是截然不同的兩個對象,比較結果全部為false應該很好理解了。




更多一次性理解C#中的==、Equals()和ReferenceEquals()的區別相關文章請注意PHP中文網!


相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板