談談C#的相等性(1)

相等性是個很重要的觀念,因為在不同的程式語言,相等性往往代表不同的涵義。

相等性就跟開水白菜一樣,外表看起來簡單,其實內容博大精深。

C#有哪些方法可以判斷相等性?

  1. 運算子 Operator== 和 Operator!=

  2. 萬物之母 System.Object 上的 virtual 方法

    public virtual bool Equals (object obj);
    public static bool Equals (object objA, object objB);
  3. 萬物之母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

Leave a Reply

avatar
  Subscribe  
Notify of