引用相等性和值相等性 在 C# 中,相等性分為引用相等性和值相等性。引用相等性是指,若兩個引用類型的變數引用的是同一個對象,則它們具有引用相等性。 // x, y, z 都是引用類型變數 object x = new object(); object y = new object(); object ...
引用相等性和值相等性
在 C# 中,相等性分為引用相等性和值相等性。引用相等性是指,若兩個引用類型的變數引用的是同一個對象,則它們具有引用相等性。// x, y, z 都是引用類型變數 object x = new object(); object y = new object(); object z = x; // 輸出 false,x 和 y 不具有引用相等性 Console.WriteLine(object.ReferenceEquals(x, y)); // 輸出 true,x 和 z 具有引用相等性 Console.WriteLine(object.ReferenceEquals(x, z)); // 輸出 true,x 和自身具有引用相等性 Console.WriteLine(object.ReferenceEquals(x, x));值相等性是指,若兩個變數----可以是引用類型或值類型----包含語義上相同的值,則它們具有值相等性。
int i = 5; int j = 6; int k = 5; // 輸出 false,i 和 j 不具有值相等性 Console.WriteLine(i.Equals(j)); // 輸出 true,i 和 k 具有值相等性 Console.WriteLine(i.Equals(k)); // 輸出 true,i 和自身具有值相等性 Console.WriteLine(i.Equals(i));
== 和 != 操作符
== 操作符用於判斷兩個變數是否相等,預設的實現是:- 對於字元串以外的引用類型,判斷變數是否具有引用相等性
- 對於值類型,判斷變數是否具有值相等性
- 對於字元串類型,判斷變數是否具有值相等性
Object.ReferenceEquals 靜態方法
Object.ReferenceEquals 靜態方法用於判斷引用相等性,它接受兩個 object 類型的參數:int i = 5; // 輸出 false,i 被裝箱兩次,是兩個不同的對象,不具有引用相等性 Console.WriteLine(object.ReferenceEquals(i, i)); // 相當於: object x = i; object y = i; Console.WriteLine(object.ReferenceEquals(x, y));
.net 框架的源碼實現中,ReferenceEquals 方法使用 == 操作符進行判斷:
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] [System.Runtime.Versioning.NonVersionable] public static bool ReferenceEquals (Object objA, Object objB) { return objA == objB; }
代碼參考:http://referencesource.microsoft.com/#mscorlib/system/object.cs,4d607d6d56a93c7e
字元串相等性
在 .net 中,字元串是引用類型,但 == 運算符和 Equals 方法都使用值相等性對字元串進行比較。預設的比較方式是區分大小寫的,有時我們希望進行不區分大小寫的比較。因此 String 類還有一個 Equals 方法的重載,允許指定如何對字元串進行相等性比較:
public bool Equals(string value, StringComparison comparisonType)
StringComparison 參數允許指定要使用的區域性、大小寫和排序規則。
字元串的例子提示相等性比較不是絕對的,兩個相同的對象,可能在一個上下文中相等,而在另一個上下文中不相等。
Object.Equals 實例方法
Object.Equals 實例方法的簽名是:public virtual bool Equals(Object obj)
這是一個虛方法,具體行為取決於是否進行了重寫。Object 中 Equals 方法的實現是,如果參數 obj 與當前對象是同一實例,則返回 true。
ValueType 重寫了 Equals 方法:若兩個值類型變數的類型相同,並且所有實例欄位相等,則它們具有值相等性。ValueType 中的 Equals 方法使用反射實現,對性能略有影響。對於自定義值類型,可考慮重寫 Equals 方法避免反射帶來的性能損失。
Object.Equals 靜態方法
這是實用工具性質的方法,用於判斷兩個變數是否相等,方法簽名是:
public static bool Equals(Object objA, Object objB)它的實現代碼如下:
public static bool Equals(Object objA, Object objB) { if (objA == objB) { return true; } if (objA == null || objB == null) { return false; } return objA.Equals(objB); }分析: 1,若兩個變數引用相同的對象,或都為 null,則返回 true。 2,若任意一個變數為 null,另一個不為 null,則返回 false。 3,若兩個變數都不為 null,並且不引用同一對象,那麼返回 objA.Equals(objB) 的結果。
重寫 Object.Equals 實例方法
重寫 Object.Equals 實例方法時,應遵循以下規則:
- 自反:x.Equals(x) 應返回 true
- 對稱:x.Equals(y) 和 y.Equals(x) 應具有相同的結果
- 傳遞:如果 x.Equals(y) 為 true,並且 y.Equals(z) 為 true,那麼 x.Equals(z) 應為 true
- 穩定:如果 x 和 y 未修改,那麼連續調用 x.Equals(y) 應具有相同的結果
- 當實參為 null 時,應始終返回 null。
- 若重寫 Equals 方法,那麼還應重寫 GetHashCode 方法,並且,兩個相等對象的 GetHashCode 方法應返回相同的值
IEquatable<T> 泛型介面
IEquatable<T> 定義類型特定的相等性比較方法,此介面只定義了一個方法,簽名為:
bool Equals(T other)
此介面是從 .net 2.0 開始伴隨泛型集合引入的。在泛型集合上調用 Contains、IndexOf、LastIndexOf 和 Remove 等方法時,將使用此介面進行相等性比較。根據 MSDN 的說明,任何可能存儲在泛型集合中的類都應實現此介面。
如果實現了 IEquatable 介面,還應重寫 Object.Equals 實例方法和 Object.GetHashCode 方法。
IEqualityComparer<T> 泛型介面和 EqualityComparer<T> 泛型類
IEqualityComparer 聲明瞭兩個方法:
bool Equals(T x, T y) int GetHashCode(T obj)
此介面允許在泛型集合中跳過 T 本身的 Equals 和 GetHashCode 實現,如果向泛型集合提供了 IEqualityComparer<T> 的實例,那麼集合將使用 IEqualityComparer<T> 的 Equals 和 GetHashCode 方法進行比較。
EqualityComparer<T> 為 IEqualityComparer<T> 泛型介面的實現提供基類。EqualityComparer<T>.Default 屬性返回預設的相等性比較器,IEquatable<T> 與泛型集合的配合實際上是在這裡起作用的:
- 若 T 實現了 IEquatable<T> 介面,則 EqualityComparer<T>.Default 使用 IEquatable<T> 介面進行相等性比較
- 否則,EqualityComparer<T>.Default 使用 Object.Equals 進行相等性比較