【发布时间】:2012-03-31 07:59:17
【问题描述】:
VS2005 文档Guidelines for Overloading Equals() and Operator == (C# Programming Guide) 部分声明
不建议在非不可变类型中覆盖运算符 ==。
较新的 .NET Framework 4 文档 Guidelines for Implementing Equals and the Equality Operator (==) 省略了该声明,尽管社区内容中的一篇文章重复了该声明并引用了旧文档。
似乎至少对于一些琐碎的可变类来说重写 Equals() 是合理的,例如
public class ImaginaryNumber
{
public double RealPart { get; set; }
public double ImaginaryPart { get; set; }
}
在数学中,具有相同实部和相同虚部的两个虚数实际上在测试相等性的时间点相等。断言它们不相等是不正确的,如果具有相同 RealPart 和 ImaginaryPart 的单独对象未被 Equals() 覆盖,则会发生这种情况。
另一方面,如果覆盖 Equals(),则还应该覆盖 GetHashCode()。如果将覆盖 Equals() 和 GetHashCode() 的 ImaginaryNumber 放置在 HashSet 中,并且可变实例更改了它的值,则该对象将不再在 HashSet 中找到。
MSDN 是否不正确地删除了关于不为非不可变类型覆盖 Equals() 和 operator== 的指南?
对于“在现实世界中”所有属性的等价性意味着对象本身是相等的(如ImaginaryNumber)的可变类型重写 Equals() 是否合理?
如果合理,当对象实例参与 HashSet 或其他依赖于 GetHashCode() 不变的东西时,如何最好地处理潜在的可变性?
更新
刚刚遇到这个in MSDN
通常,当类型的对象是 期望被添加到某种集合中,或者当他们的 主要目的是存储一组字段或属性。你可以 将您对价值平等的定义建立在对所有 类型中的字段和属性,或者您可以将定义基于 子集。但在任何一种情况下,在类和结构中,你的 实施应遵循等效的五项保证:
【问题讨论】:
-
我认为
ImaginaryNumber是可变类型是不合理的。 -
实际上,您可能应该将 ImaginaryNumber 实现为不可变的值类型(结构)。
-
int、long、double等...不是可变的。5是5- 您无法更改它的含义。 -
@EricJ。 变量
i的值 改变了,但Int320仍然是0。 -
为什么 ComplexNumber 应该是不可变的示例:考虑“ComplexNumber a, b, c;”。 Numbers 的期望是 a、b、c 是独立的。 “a = 新的 ComplexNumber(1, 2); b = a;”然后“a.RealPart = -1;”这也将改变 b,除非将 ComplexNumber 定义为结构。或者将 RealPart 设为只读,不允许设置 a.RealPart。然后更改为 a 由“a = new ComplexNumber(-1, a.ImaginaryPart);”完成可以制作一个方便的方法 public ComplexNumber SetReal(double value) { return new ComplexNumber(value, this.ImaginaryPart); }。调用:“a = a.SetReal(-1);”
标签: c# equals gethashcode