== Equals ReferenceEquals 三個相等性測試,是.NET提供給程序員使用的三個方法,他們之間有什麼聯系和區別,你真的仔細研究過?雖然之前也多多少少知道一點,但是有時候又難免混淆他們之間的概念和所適用的場合,決定做一個總結系統的描述這三個寶寶
在編程中實際上我們只需要這兩種比較,c#中類型也就這兩種
(1)值類型的比較:一般我們就是判斷兩個值類型實例的各自包含的值是否相等
(2)引用類型的比較:由於引用類型在內存中的分布有兩部分,一個是引用類型的引用(存在於線程棧中),一個是引用類型的值(存在於托管堆);所以我們比較引用類型也就存在兩種比較
默認情況下:值類型比較的是兩個值是否相等(不裝箱情況下),引用類型比較的是兩個引用是否相等。
定義:靜態相等符號,對應存在的!=,這個符號是一個可以重載的二元操作符,可以用於比較兩個對象是否相等。使用==比較對象時,C#在編譯時就決定了所比較的類型,而且不會執行任何虛方法(Object.Equals)。這是大家所期望的相等行比較。
注意:但是某些內置的引用類型重載了==符號,例如string就重載==,使其比較的不是兩個字符串的引用,而是比較的兩個字符串字面量是否相等,如下圖,所以對於引用類型最好不要使用==符號進行相等性比較,避免混淆。【對於引用類型利用==除了string是比較其值外,其余都是比較其引用,因為string是經常需要操作,所以會直接比較其值,所以會對其特殊對待,所以如果遇見特殊的引用類型需要查看一下是否進行了==重載,默認情況大家都可以把==在比較引用類型時當成比較引用!】
值類型的==比較:雖然i和j在棧上具有不同的內存空間,但是他們的代數值都為5;m和n類型被自動轉換並比較代數值
int i = 5; int j = 5; Console.WriteLine(i == j);//值類型比較代數值 輸出True int m = 6; double n = 6.0; Console.WriteLine(m == n);//類型自動轉換並比較數值 輸出True==值類型比較
引用類型==比較:如下代碼,兩個object對象都在堆上申請了空間,在線程棧上存在兩個不同的引用,所以輸出結果為False
object obj1 = new object(); object obj2 = new object(); Console.WriteLine(obj2==obj1);//引用類型比較引用 輸出False==引用類型比較
3.2 Equals
定義:Equals屬於Object的實例方法,用於比較兩個對象的引用是否相等,注意:對於Object對象比較的是引用!
然而對於值類型,類型相同(不會進行類型自動轉換),並且數值相同(對於struct的每個成員都必須相同),則Equals返回 true,否則返回false。這是為什麼呢? 這是因為內置的值類型都重寫了Object.Equals方法,所以值類型的Equals方法與引用類型的Equals就產生了不同的效果。
Equals在程序運行時決定比較的類型--根據對象的實際類型進行比較,根據對象的類型調用他們各自的Equals虛方法。
int i = 5; int j = 5; Console.WriteLine(i.Equals(j));//值類型比較 輸出True int m = 6; double n = 6.0; Console.WriteLine(m.Equals(n));//類型不會自動轉換並比較數值 輸出False object obj1 = new object(); object obj2 = new object(); Console.WriteLine(obj2.Equals(obj1));//引用類型比較 輸出False Console.WriteLine(obj2.Equals(string.Empty));//輸出False,比較量對象的類型不同直接返回FalseEquals比較
3.3 ReferenceEquals
定義:Object的靜態方法,比較兩對象的引用是否相等,值類型和引用類型都是一樣。
int i = 5; int j = 5; Console.WriteLine(object.ReferenceEquals(i, j));//輸出False int m = 6; double n = 6.0; Console.WriteLine(object.ReferenceEquals(m, n));//輸出False object obj1 = new object(); object obj2 = new object(); Console.WriteLine(object.ReferenceEquals(obj1, obj2));//輸出FalseReferenceEquals比較
通過以上的探討我們知道
ReferenceEquals比較對象的引用是否相同,而且是安全的比較
==和Equals異同
相同點: 對於值類型 都是比較代數值是否相等
不同點:(1)對於值類型比較,==會進行類型的自動轉換,然後比較代數值,Equals則不會進行轉換,先比較類型,再比較值,如果類型不同直接返回false
(2)==比較是安全的比較,也就是說兩對象為任何值都可以進行比較,不會拋出異常;而Equals的比較則是不安全的,由於在Equals在運行時才會進行真正的比較,有可能調用Equals的調用者是NULL,編譯通過,但是運行時則會拋出異常
所以對於引用類型是要使用實例的Equals進行比較時,一定不要忘記檢查調用者對象是否為空。而Object提供的靜態Equals方法也是安全的不需要檢查,下面的方法等效於Object提供的靜態Equals方法
public static bool AreEqual(object obj1, object obj2) { if (obj1 == null) return obj2 == null; return obj1.Equals(obj2); }