考虑这个可变的Person类:
class Person { readonly int Id; string FirstName { get; set; } string LastName { get; set; } string Address { get; set; } // ... }
表示完全相同的人的两个对象将始终具有相同的Id,但是其他字段可能随时间(即,地址更改之前/之后)而不同.
对于这个对象,Equals可以被定义为意味着不同的东西:
>值平等:所有字段是相等的(两个对象表示同一个人,但是不同的地址将返回false)
>身份平等:身份相同(两个对象代表同一个人,但是不同的地址将返回真实)
>参考平等:即不执行Equals.
问题:这个课程中哪个(如果有的话)比较喜欢? (或者也许这个问题应该是,“这个类的大多数客户端如何期待Equals()的行为?”)
笔记:
>使用Value Equality使得在Hashset或Dictionary中更难使用这个类
>使用Identity Equality使Equals和= =操作符之间的关系变得奇怪(即,对于Equals(),两个Person对象(p1和p2)的检查返回true后,您可能仍然希望将引用更新为指向“较新” Person对象因为它不是等价的).例如,下面的代码看起来很奇怪 – 似乎没有什么,但它实际上是删除p1并添加了p2:
HashSet<Person> people = new HashSet<Person>(); people.Add(p1); // ... p2 is an new object that has the same Id as p1 but different Address people.Remove(p2); people.Add(p2);
相关问题:
> Why does Microsoft recommend skip implementing equality operator for reference types?
> C# difference between == and Equals()
> When Should a .NET Class Override Equals()? When Should it Not?
> Simplify Overriding Equals(),GetHashCode() in C# for Better Maintainability
解决方法
>当使用像Person这样的东西作为一个哈希集中的字典键的情况的数量是最小的
>并且当您这样做时,您可以提供一个遵循您希望遵循的实际规则的自定义比较器
>但大多数情况下,我会使用int id作为字典(等)中的关键字
>使用引用等式意味着x == y给出相同的结果,无论x / y是Person还是对象,或者在通用方法中都是T
>只要Equals和GetHashCode是兼容的,大多数事情只会解决问题,一个简单的方法是不要覆盖它们
但是请注意,我总是建议相反的值类型,即明确地覆盖Equals / GetHashCode;但是,编写一个结构体真的很少见