天天看点

【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