TIPS-比對.NET Reference Type物件是否相等
3 |
跟同事討論到自訂類別物件的比對問題,原則上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
Comments
# by hunterpo
黑大您好, 觀察您的 HiClass 複寫 operator == 那一段: "...|| (object)a == null || (object)b == null)" 感覺較為不合理,再比對 您提供的 msdn 文件內容,它也是檢查 a 或 b 只有一為 null 即回傳 false。 雖說不影響最後測試結果啦...
# by Jeffrey
to hunterpo, 抱歉,程式寫到昏頭了,發現原來的寫法確實有問題,已經修改並感謝您的指正!!
# by Ark
感覺這一課和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