天天看點

【C#】如何比較兩個對象是否相等(重寫Equals方法)

問題: 寫單元測試時,需要對比兩個對象是否相等,如果使用

Assert.AreEqual(mockclass1, class1)

永遠無法通過。

原因: 這裡使用了

object

預設的

Equals

方法,必須要引用同一個對象,才會傳回

true

。預設的

Equals

方法實作的隻是同一性(identity),而不是相等性(equality)。

合理的

Equals

方法本應該這樣實作:

  1. 如果

    obj

    實參為空,就傳回

    false

    ,因為調用的是非靜态

    Equals

    方法,

    this

    辨別的目前對象肯定不為空;
  2. 如果

    this

    obj

    實參引用同一個對象,就傳回

    true

    。在比較大量字段時,這一步有助于提升性能;
  3. 如果

    this

    obj

    實參引用不同類型的對象,就傳回

    false

  4. 針對類型定義的每個執行個體字段,将

    this

    對象中的值與

    obj

    對象中的值進行比較,任何字段不相等,傳回

    false

  5. 調用基類的

    Equals

    方法比較它定義的任何字段,傳回基類的

    Equals

    結果。

由于

Microsoft

并沒有這樣實作

Equals

,是以需要針對不同的對象重寫

Equals

方法,為了仍然能測試同一性,

Object

提供了靜态方法

ReferenceEquals

同一性

檢查同一性(看兩個引用是否指向同一個對象),務必調用

ReferenceEquals

,不應該使用

==

操作符,因為類型可能重載了操作符。

相等性

重寫

Equals

方法時,除了上文所講的,還應該做下面幾件事:

  • 讓類型實作

    System.IEquatable<T>

    接口的

    Equals

    方法。

    這個泛型接口允許定義類型安全的

    Equals

    方法,在重寫的

    Equals(object obj)

    方法中調用這個類型安全的方法。
  • 重載

    ==

    !=

    操作符方法。
  • 如果需要排序而比較類型的執行個體,還應該實作

    System.IComparable

    CompareTo

    方法以及各種比較操作符。
  • 重寫類型的

    GetHashCode

    方法。

    由于在

    System.Collections.Hashtable

    System.Collections.Generic.Dictionary

    以及其他一些集合的實作中,要求兩個對象必須具有相同的哈希碼才被視為相等。

具體例子如下,完整可參考 MSDN IEquatable.Equals(T) Method:

public class Person : IEquatable<Person>
{
    private string _name;
    private string _id;

    public Person(string name, string id)
    {
        _name = name;
        _id = id;
    }

    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }

    public string Id
    {
        get{ return _id; }
        set{ _id = value; }
    }

    //自定義的Equals方法
    public bool Equals(Person other)
    {
        if (other == null) return false;

        if (_name == other.Name && _id == other.Id)
            return true;
        else
            return false;
    }
    //重寫基類中的Equals方法
    public override bool Equals(object obj)
    {
        if (obj == null) return false;

        Person personObj = obj as Person;
        if (personObj == null)
            return false;
        else
            return Equals(personObj);
    }
    
    public override int GetHashCode()
    {
        return _name.GetHashCode() ^ _id.GetHashCode();
    }
}
           

拓展閱讀:

https://www.cnblogs.com/yang_sy/archive/2014/03/07/3582946.html