談談C#的相等性(1)
相等性是個很重要的觀念,因為在不同的程式語言,相等性往往代表不同的涵義。
相等性就跟開水白菜一樣,外表看起來簡單,其實內容博大精深。
C#有哪些方法可以判斷相等性?
-
運算子 Operator== 和 Operator!=
-
萬物之母 System.Object 上的 virtual 方法
public virtual bool Equals (object obj);
public static bool Equals (object objA, object objB); -
萬物之母System.Object上的 static 方法
public static bool ReferenceEquals (object objA, object objB);
在探討這三種方法的差別以前,我們先往後退一步,給相等性兩個不同的定義。
兩種相等性
Reference Equality
第一種是參考相等,代表兩個物件參考記憶體內相同的底層物件。
Test a = new Test() {Num = 1, Str = "Hi"};
Test b = new Test() {Num = 1, Str = "Hi"};
bool areEqual = System.Object.ReferenceEquals(a, b); // false
b = a;
areEqual = System.Object.ReferenceEquals(a, b); // true
System.Object.ReferenceEquals 用於判定兩物件是否參考相等。
一個重要的觀念是,參考相等只有對Reference Type物件有意義,對於Value Type物件而言,assignment會複製其值,底層依舊是兩個相同內容的不同物件,所以Reference Equals會永遠回傳false。
將value type傳入System.Object.ReferenceEquals時,會發生Boxing。傳入的兩個整數1會各自被Boxing成object,放置在heap上進行reference equality比較,結果為false。
System.Object.ReferenceEquals(1, 1); // False
另外null也是一種reference,代表沒有參考到任何物件。是所有reference type物件的預設值。所以
System.Object.ReferenceEquals(null, null); // true
Value Equality
Value Equality概念很簡單,兩個物件包含的值內容相等就是為相等。 對於那些primitive value type,像是int, bool等,可以直接用 operator ==
判定相等即可。
int a = 2;
int b = 2;
a == b; // true
但對於比較複雜的型別,如struct, class等,直觀的想法是所有的field都包含相同的值,視為value equality。但並不保證一定如此。實際情況還是要看struct, class對於Value Equality的定義。
另外特別注意,浮點數的Value Equality可能會因為精度問題而出事。就不在此贅述了。幾乎所有的語言都有這樣的問題。
0.1 + 0.2 == 0.3 // false