== 运算符的行为是否应该与 Equals() 完全相同?

Should == operator behave exactly as Equals()?

让我们考虑 Polygon class。大多数情况下检查相等性应该比较引用,但在很多情况下值相等性会派上用场(比如用 Assert.AreEqual 比较两个多边形时)。

我的想法是使值相等性在某种程度上次于引用相等性。在这种情况下,很明显 ==operator 应该保留其默认的引用检查实现。

那么object.Equals()IEquatable<Polygon>.Equals()呢? MSDN 并不暗示 ==.Equals() 应该做同样的事情,但仍然 - 它不会使 Polygon 对象的行为过于模棱两可吗?

此外,Polygon class 是可变的。

MSDN差不多清楚了

To check for reference equality, use ReferenceEquals. To check for value equality, you should generally use Equals. However, Equals as it is implemented by Object just performs a reference identity check. It is therefore important, when you call Equals, to verify whether the type overrides it to provide value equality semantics. When you create your own types, you should override Equals.


By default, the operator == tests for reference equality by determining if two references indicate the same object, so reference types do not need to implement operator == in order to gain this functionality. When a type is immutable, meaning the data contained in the instance cannot be changed, overloading operator == to compare value equality instead of reference equality can be useful because, as immutable objects, they can be considered the same as long as they have the same value. Overriding operator == in non-immutable types is not recommended.

IEquatable文档也很清楚

Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.

在 .NET(以及 Java)中进行相等性测试的一个主要困难是有两个有用的等价关系,每个都基于一个可以对任何 class 对象合理提出的问题,但是 .NET 对于应该由 EqualsGetHashCode 应该回答的问题或关系进行封装并不一致。问题是:

  1. 无论你发生什么事,你是否永远永远等同于某个特定引用所标识的对象。

  2. 你会认为自己等同于某个特定引用所标识的对象,除非或直到引用你的东西做了会影响这种等价的事情。

对于不可变对象,两种关系都应测试值是否相等。对于可变对象,第一个问题应测试引用等价性,第二个问题应测试值相​​等性。对于持有对可变类型对象的引用但没有人会改变的不可变对象,这两个问题都应测试该封装对象的值相等性。

我个人的建议是可变对象不覆盖 Object.Equals,但它们提供静态 属性,returns 和 IEqualityComparer 来测试值相等性。这将需要 任何不可变地封装可变对象的对象都必须 获取 IEqualityComparer 以能够报告封装对象的 值等价关系本身,但具有 IEqualityComparer 可以将这些东西存储在例如Dictionary 已提供 它们永远不会被修改。