欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【C#】如何比较两个对象是否相等(重写Equals方法)

程序员文章站 2022-06-10 20:29:03
...

问题: 写单元测试时,需要对比两个对象是否相等,如果使用Assert.AreEqual(mockclass1, class1)永远无法通过。

原因: 这里使用了object默认的Equals方法,必须要引用同一个对象,才会返回true 。默认的Equals方法实现的只是同一性(identity),而不是相等性(equality)

合理的Equals方法本应该这样实现:

  1. 如果obj实参为空,就返回false,因为调用的是非静态Equals方法,this标识的当前对象肯定不为空;
  2. 如果thisobj实参引用同一个对象,就返回true。在比较大量字段时,这一步有助于提升性能;
  3. 如果thisobj实参引用不同类型的对象,就返回false
  4. 针对类型定义的每个实例字段,将this对象中的值与obj对象中的值进行比较,任何字段不相等,返回false
  5. 调用基类的Equals方法比较它定义的任何字段,返回基类的Equals结果。

由于Microsoft并没有这样实现Equals,所以需要针对不同的对象重写Equals方法,为了仍然能测试同一性,Object提供了静态方法ReferenceEquals

同一性

检查同一性(看两个引用是否指向同一个对象),务必调用 ReferenceEquals,不应该使用==操作符,因为类型可能重载了操作符。

相等性

重写Equals方法时,除了上文所讲的,还应该做下面几件事:

  • 让类型实现System.IEquatable<T>接口的Equals方法。
    这个泛型接口允许定义类型安全的Equals方法,在重写的Equals(object obj)方法中调用这个类型安全的方法。
  • 重载==!=操作符方法。
  • 如果需要排序而比较类型的实例,还应该实现System.IComparableCompareTo方法以及各种比较操作符。
  • 重写类型的GetHashCode方法。
    由于在System.Collections.HashtableSystem.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();
    }
}