TIPS-比對.NET Reference Type物件是否相等

跟同事討論到自訂類別物件的比對問題,原則上Reference Type類別的物件,除非兩個變數指向同一個Instance,使用==或Equals(...)測試都會得到false,就算是兩個Instance的內容分毫不差也是枉然。當物件被當成WCF/Web Service參數來回傳送,背地裡會被序列化再還原,便會變成內容相同的另一個Instance(其實只要在不同Process間傳遞,因無法共享記憶體,就一定會產生這種結果),此時若直接使用==或Equals比對,得到的結果永遠為不相同。

我們可以透過覆寫Equals及==、!=運算子的方式,將"兩個物件是否相同"的定義調整為自訂比對條件。過去只知其然,今天就順道實作一個測試來驗證。

在以下程式中,我宣告了兩個類別: 一般寫法的MyClass及精心特調的HiClass(多寫了好多Code,所以變得比較高級 XD),HiClass實作了Equals、==及!=,透過比對Id屬性來決定物件是否相等。

using System;
public class CSharpLab
{
    class MyClass 
    { 
        public string Id;
        public MyClass(string id) 
        {
            Id = id;
        }
    }
    class HiClass
    { 
        public string Id;
        public HiClass(string id) 
        {
            Id = id;
        }
//REF:http://msdn.microsoft.com/en-us/library/ms173147%28VS.80%29.aspx
        public override bool Equals(object obj) {
            if (obj == null) return false;
            HiClass t = obj as HiClass;
            if ((object)t == null) return false;
            return t.Id == this.Id;
        }
        public bool Equals(HiClass c) {
            if ((object)c == null) return false;
            return this.Id == c.Id;
        }
        public override int GetHashCode() 
        {
            return this.Id.GetHashCode();
        }
        public static bool operator ==(HiClass a, HiClass b)
        {
            if (object.ReferenceEquals(a, b)) return true; 
            if ((object)a == null || (object)b == null) 
                return false;
            return a.Equals(b);
        }
        public static bool operator !=(HiClass a, HiClass b) 
        {
            return !(a==b);
        }
    }
    public static void Test()
    {
        MyClass a = new MyClass("A");
        MyClass b = new MyClass("A");
        MyClass c = a;
        Console.WriteLine("a == b -> {0}", a == b);
        Console.WriteLine("a.Equals(b) -> {0}", a.Equals(b));
        Console.WriteLine("a == c -> {0}", a == c);
        Console.WriteLine("a.Equals(c) -> {0}", a.Equals(c));
        
        HiClass d = new HiClass("A");
        HiClass e = new HiClass("A");
        Console.WriteLine("d == e -> {0}", d == e);
        Console.WriteLine("d.Equals(e) -> {0}", d.Equals(e));
        Console.WriteLine("object.ReferenceEquals(d, e) -> {0}", 
            object.ReferenceEquals(d, e));
    }
}

測試結果如下,大家看看是否符合自己的預期,若一切都在你掌握中,就算差不多已搞懂Reference Type的比對原則了。
a == b -> False
a.Equals(b) -> False
a == c -> True
a.Equals(c) -> True
d == e -> True
d.Equals(e) -> True
object.ReferenceEquals(d, e) -> False

歡迎推文分享:
Published 17 February 2011 06:36 AM 由 Jeffrey
Filed under: ,
Views: 9,556



意見

# hunterpo said on 16 February, 2011 08:41 PM

黑大您好,

觀察您的 HiClass 複寫 operator == 那一段:

       "...|| (object)a == null || (object)b == null)"

感覺較為不合理,再比對 您提供的 msdn 文件內容,它也是檢查 a 或 b 只有一為 null 即回傳 false。

雖說不影響最後測試結果啦...

# Jeffrey said on 17 February, 2011 05:52 AM

to hunterpo, 抱歉,程式寫到昏頭了,發現原來的寫法確實有問題,已經修改並感謝您的指正!!

# Ark said on 18 February, 2011 03:47 AM

感覺這一課和struct 放一起會更有fu

改成 struct

struct mySt

{

   public string Id;

   public mySt(string id)

   {

       Id = id;

   }

}

   mySt x = new mySt("A");

   mySt y = new mySt("A");

   x.Equals(y) -> True

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 
(提醒: 因快取機制,您的留言幾分鐘後才會顯示在網站,請耐心稍候)

5 + 3 =

搜尋

Go

<February 2011>
SunMonTueWedThuFriSat
303112345
6789101112
13141516171819
20212223242526
272812345
6789101112
 
RSS
創用 CC 授權條款
【廣告】
twMVC
最新回應

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


Syndication