如果没有为引用类型做任何特殊操作,则Equals()意味着引用相等(即相同的对象).如果我选择覆盖Equals()引用类型,它是否总是意味着两个对象的值是等价的?
考虑这个可变性 Person类:
class Person
{
readonly int Id;
string FirstName { get; set; }
string LastName { get; set; }
string Address { get; set; }
// ...
}
Run Code Online (Sandbox Code Playgroud)
表示完全相同的人的两个对象将始终具有相同的Id,但是其他字段可能随时间不同(即,在地址改变之前/之后).
对于这个对象,Equals可以定义为不同的东西:
Ids相等(代表同一个人但具有不同地址的两个对象将返回true)问题:这个课程中哪些(如果有的话)更适合?(或许问题应该是,"这个班级的大多数客户如何期望Equals()表现?")
笔记:
Hashsetor中使用这个类更加困难Dictionary使用Identity Equality使得Equals和=运算符之间的关系变得奇怪(即在检查两个Person对象(p1和p2)之后返回true)Equals(),您可能仍然希望更新引用以指向"较新的"Person对象,因为它是不等值).例如,以下代码读取奇怪 - 似乎它什么都不做,但它实际上是删除p1并添加p2:
HashSet<Person> people = new HashSet<Person>();
people.Add(p1);
// ... p2 is an new object that has the same Id as p1 …Run Code Online (Sandbox Code Playgroud)我们知道所有类型都从它们的基类继承Equals,即Object.
每个Microsoft文档:
仅当被比较的项目引用内存中的相同项目时,Equals才返回true.
所以我们使用Equals()来比较对象引用,而不是对象的状态.
通常,仅当被比较的对象具有相同的内部状态值时,才会重写此方法以返回true.
我的问题:两个对象可以指向内存中的相同项目但是具有不同的状态吗?如果没有,为什么要覆盖Equals?
感谢您的回答清楚.对于未来的读者,这里是我们覆盖的原因的一个例子:
Employee A=New Employee();
Employee B=New Employee();
Run Code Online (Sandbox Code Playgroud)
在这种情况下,A和B始终指向不同的内存,因此Equals始终为false.
但是如果:
A.SSN=B.SSN;
A.LiceneNumber=B.LiceneNumber;
Run Code Online (Sandbox Code Playgroud)
这两个员工是同一个人,在这种情况下,我们需要检查状态,因此重写Equals.
所以在我的情况下,问题的关键在于:两个不同的对象可能存储在两个不同的位置,但仍然引用同一个实体(在我的例子中是Employee).
我发现我的自我重写Equals()并GetHashCode()经常实现具有相同属性值的业务对象相等的语义.这会导致代码重复写入并且易于维护(属性被添加,并且一个/两个覆盖都不会更新).
代码最终看起来像这样(欢迎对实现的评论):
public override bool Equals(object obj)
{
if (object.ReferenceEquals(this, obj)) return true;
MyDerived other = obj as MyDerived;
if (other == null) return false;
bool baseEquals = base.Equals((MyBase)other);
return (baseEquals &&
this.MyIntProp == other.MyIntProp &&
this.MyStringProp == other.MyStringProp &&
this.MyCollectionProp.IsEquivalentTo(other.MyCollectionProp) && // See http://stackoverflow.com/a/9658866/141172
this.MyContainedClass.Equals(other.MyContainedClass));
}
public override int GetHashCode()
{
int hashOfMyCollectionProp = 0;
// http://computinglife.wordpress.com/2008/11/20/why-do-hash-functions-use-prime-numbers/
// BUT... is it worth the extra math given that elem.GetHashCode() should be well-distributed?
int bitSpreader = 31; …Run Code Online (Sandbox Code Playgroud)