【C#】如何比较两个对象是否相等(重写Equals方法)
程序员文章站
2022-06-10 20:29:03
...
问题: 写单元测试时,需要对比两个对象是否相等,如果使用Assert.AreEqual(mockclass1, class1)
永远无法通过。
原因: 这里使用了object
默认的Equals
方法,必须要引用同一个对象,才会返回true
。默认的Equals
方法实现的只是同一性(identity),而不是相等性(equality)。
合理的Equals
方法本应该这样实现:
- 如果
obj
实参为空,就返回false
,因为调用的是非静态Equals
方法,this
标识的当前对象肯定不为空; - 如果
this
和obj
实参引用同一个对象,就返回true
。在比较大量字段时,这一步有助于提升性能; - 如果
this
和obj
实参引用不同类型的对象,就返回false
; - 针对类型定义的每个实例字段,将
this
对象中的值与obj
对象中的值进行比较,任何字段不相等,返回false
; - 调用基类的
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();
}
}
下一篇: C# Exists判断集合中某个属性的值