.Net(C#)中,對象的相等比較問題

來源:互聯網
上載者:User

以前一直沒有關心這個問題,被別人問起,特記錄一下. ( From csdn)

在討論了運算子,並簡要介紹了等於運算子後,就應考慮在處理類和結構的執行個體時相等意味著什麼。理解對象相等比較的機制對編寫邏輯運算式非常重要,另外,對實現運算子多載和資料類型轉換也非常重要,本章的後面將討論運算子多載。

對象相等比較的機制對於參考型別(類的執行個體)的比較和實值型別(基礎資料型別 (Elementary Data Type),結構或枚舉的執行個體)的比較來說是不同的。下面分別介紹參考型別和實值型別的相等比較。

5.3.1 參考型別的相等比較

System.Object的一個初看上去令人驚訝的方面是它定義了3個不同的方法,來比較對象的相等性:ReferenceEquals()和Equals()的兩個版本。再加上比較子==,實際上有4種進行相等比較的方式。這些方法有一些微妙的區別,下面就介紹這些方法。

1. ReferenceEquals()方法

ReferenceEquals()是一個靜態方法,測試兩個引用是否指向類的同一個執行個體,即兩個引用是否包含記憶體中的相同地址。作為靜態方法,它不能重寫,所以只能使用System.Object的實現代碼。如果提供的兩個引用指向同一個對象執行個體,ReferenceEquals()總是返回true,否則就返回false。但是它認為null等於null:

SomeClass x, y;

x = new SomeClass();

y = new SomeClass();

bool B1 = ReferenceEquals(null, null);                //return true

bool B2 = ReferenceEquals(null, x);                //return false

bool B3 = ReferenceEquals(x, y);                  //return false because x and y

                                            //point to different objects

2. 虛擬Equals()方法

Equals()虛擬版本的System.Object實現代碼也比較引用。但因為這個方法是虛擬,所以可以在自己的類中重寫它,按值來比較對象。特別是如果希望類的執行個體用作字典中的鍵,就需要重寫這個方法,以比較值。否則,根據重寫Object.GetHashCode()的方式,包含對象的字典類要麼不工作,要麼工作的效率非常低。在重寫Equals()方法時要注意,重寫的代碼不會拋出異常。這是因為如果拋出異常,字典類就會出問題,一些在內部調用這個方法的.NET基類也可能出問題。

3. 靜態Equals()方法

Equals()的靜態版本與其虛擬執行個體版本的作用相同,其區別是靜態版本帶有兩個參數,並對它們進行相等比較。這個方法可以處理兩個對象中有一個是null的情況,因此,如果一個對象可能是null,這個方法就可以拋出異常,提供了額外的保護。靜態重載版本首先要檢查它傳送的引用是否為null。如果它們都是null,就返回true(因為null與null相等)。如果只有一個引用是null,就返回false。如果兩個引用都指向某個對象,它就調用Equals()的虛擬執行個體版本。這表示在重寫Equals()的執行個體版本時,其效果相當於也重寫了靜態版本。

4. 比較子==

最好將比較子看作是嚴格值比較和嚴格引用比較之間的中間選項。在大多數情況下,下面的代碼:

bool b = (x == y);          //x, y object references

表示比較引用。但是,如果把一些類看作值,其含義就會比較直觀。在這些情況下,最好重寫比較子,以執行值的比較。後面將討論運算子的重載,但顯然它的一個例子是System.String類,Microsoft重寫了這個運算子,比較字串的內容,而不是它們的引用。

5.3.2 實值型別的相等比較

在進行實值型別的相等比較時,採用與參考型別相同的規則:ReferenceEquals()用於比較引用,Equals()用於比較值,比較子可以看作是一個中間項。但最大的區別是實值型別需要裝箱,才能把它們轉換為引用,才能對它們執行方法。另外,Microsoft已經在System.ValueType類中重載了執行個體方法Equals(),以便對實值型別進行合適的相等測試。如果調用sA.Equals(sB),其中sA和sB是某個結構的執行個體,則根據sA和sB是否在其所有的欄位中包含相同的值,而返回true或false。另一方面,在預設情況下,不能對自己的結構重載==運算子。在運算式中使用(sA==sB)會導致一個編譯錯誤,除非在代碼中為結構提供了==的重載版本。

另外,ReferenceEquals()在應用於實值型別時,總是返回false,因為為了調用這個方法,實值型別需要裝箱到對象中。即使使用下面的代碼:

bool b = ReferenceEquals(v, v);          //v is a variable of some value type

也會返回false,因為在轉換每個參數時,v都會被單獨裝箱,這意味著會得到不同的引用。調用ReferenceEquals()來比較實值型別實際上沒有什麼意義。

儘管System.ValueType提供的Equals()預設重載肯定足以應付絕大多數自訂的結構,但仍可以為自己的結構重寫它,以提高效能。另外,如果實值型別包含作為欄位的參考型別,就需要重寫Equals(),以便為這些欄位提供合適的語義,因為Equals()的預設重寫版本僅比較它們的地址。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.