[C#.NET] 利用序列化 比較兩物件是否相等

  • 18470
  • 0
  • C#
  • 2012-12-18

[C#.NET] 利用序列化 比較兩物件是否相等

參考型別是不能直接拿來做相等判斷,假使我直接調用 object.Equals 方法,用來判斷兩物件裡的值是否相等。

程式碼如下:這樣寫只會得到 false

參考:http://www.dotblogs.com.tw/larrynung/archive/2009/10/21/11168.aspx


{
    Person target = new Person()
    {
        Age = 18,
        Address = "地球村",
        Name = new Name("余", "小章"),
    };

    Person expected = new Person()
    {
        Age = 18,
        Address = "地球村",
        Name = new Name("余", "小章"),
    };

    if (expected.Equals(target))
    {
        MessageBox.Show("兩物件的值相等");
    }
    else
    {
        MessageBox.Show("兩物件的值不相等");
    }
}
定義類別如下:

public class Name
{
    public string FristName { get; set; }

    public string LastName { get; set; }

    public Name()
    {
    }

    public Name(string frisName, string lastName)
    {
        this.FristName = frisName;
        this.LastName = lastName;
    }
}

[Serializable]
public class Person
{
    public int Age { get; set; }

    public string Address { get; set; }

    public Name Name { get; set; }
}
到底要怎麼做才能比對兩個物件的值是否相等?我想這是很多人心中的疑惑。

解決方案:
假如我們要比較兩個物件,我們可以覆寫 object.Equals 方法,用來告知 CLR,想要比較兩個物件裡的什麼欄位。
http://msdn.microsoft.com/zh-tw/library/dd183752.aspx
http://msdn.microsoft.com/zh-tw/library/dd183755.aspx
http://www.dotblogs.com.tw/yc421206/archive/2012/05/25/72398.aspx
比如這樣寫:

{
    if (this.Age != ((Person)obj).Age)
    {
        return false;
    }
    return true;
}
PS1.假若覆寫了 Equals 方法也別忘了處理 GetHashCode 方法。

{
    return Age.GetHashCode() ^ Address.GetHashCode() ^ Name.FristName.GetHashCode() ^ Name.LastName.GetHashCode();
}

PS2.實作 GetHashCode 可參考以下規則:
http://www.dotblogs.com.tw/larrynung/archive/2009/12/16/12489.aspx

或是實作 IEqualityComparer 介面:
http://msdn.microsoft.com/zh-tw/library/system.collections.iequalitycomparer(v=vs.80).aspx

PS3.沒事的話不要覆寫它們兩個,有太多的功能會用到它們,若沒寫好可能會造成癱瘓。

這時,我需要每個欄位都比對正確,才算是相同的物件,若是按照上面的方式來做,可想而知 Equals 方法裡會有很多的判斷式,為了減少 Hard Code 的時間,在這裡提供利用序列化的技巧來處理。
程式碼如下:

public class Person
{
    public int Age { get; set; }

    public string Address { get; set; }

    public Name Name { get; set; }

    public override bool Equals(object obj)
    {
        var targetArray = getObjectByte(this);
        var expectedArray = getObjectByte(obj);
        var equals = expectedArray.SequenceEqual(targetArray);
        return equals;
    }

    private byte[] getObjectByte(object model)
    {
        using (MemoryStream memory = new MemoryStream())
        {
            XmlSerializer xs = new XmlSerializer(model.GetType());
            xs.Serialize(memory, model);
            var array = memory.ToArray();
            return array;
        }
    }
}
可以看到 Equals 方法裡,使用序列化將物件轉成Byte[],然後再比對兩物件的Byte[],這樣幫我們縮短不少 Hard Code 的時間,假使爾後類別新增欄位,也不必再另外處理它。
當然,也可以將它弄成擴充方法,讓所有的物件都享有這功能

{
    public static bool EqualsObject(this object obj1, object obj2)
    {
        var targetArray = getObjectByte(obj1);
        var expectedArray = getObjectByte(obj2);
        var equals = expectedArray.SequenceEqual(targetArray);
        return equals;
    }

    private static byte[] getObjectByte(object model)
    {
        using (MemoryStream memory = new MemoryStream())
        {
            XmlSerializer xs = new XmlSerializer(model.GetType());
            xs.Serialize(memory, model);
            var array = memory.ToArray();
            return array;
        }
    }
}
如此一來便能比較兩個物件裡的值是否相等。
序列化相關應用:
[C#.NET] 利用序列化進行類別深複製- 余小章@ 大內殿堂- 點部落
[C#.NET] 物件oject/class 的加解密- 余小章@ 大內殿堂- 點部落
[C#.NET][Winform] 序列化表單 - 多國語言應用程式 / Form Serialize - Multiple Languages Application

若有謬誤,煩請告知,新手發帖請多包涵


Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET

Image result for microsoft+mvp+logo