什么时候==会以不同的方式覆盖.equals?

w00*_*977 15 c# equality

我理解==和.equals之间的区别.这里还有很多其他问题可以解释细节上的差异,例如这一点:.Equals和==这一点之间的区别是什么:其他许多人之间的比例平等.

我的问题是:为什么他们两个(我意识到必须有一个很好的理由) - 他们似乎都做同样的事情(除非被覆盖不同).

什么时候==会以不同的方式超载.equals被覆盖?

Jon*_*eet 37

==在编译时静态绑定,因为运算符始终是静态的.你重载运算符 - 你不能覆盖它们.Equals(object)以多态方式执行,因为它被覆盖了.

就你什么时候想要它们而言......

引用类型通常会覆盖Equals但根本不会过载==.容易区分"这两个引用引用相同的对象"和"这两个引用引用相同的对象"之间的区别可能很有用.(你可以用ReferenceEquals你想成为-和埃里克在评论中指出,这是更清楚的如果需要的话,当然可以.)真的,当你这样做,你心里清楚左右.

double对NaN值有这种行为; ==(double, double)当任一操作数都是时,它总是返回false NaN,即使它们是相同的NaN.Equals如果不使合同无效,就不能这样做.(不可否认GetHashCode,不同的NaN价值会被打破,但那是另一回事 ......)

我个人不记得曾经实施过它们以给出不同的结果.

  • 在我自己的代码中,如果我的意思是引用等于并且有*任何*机会它可能与值相等混淆,那么我称之为`ReferenceEquals`.这样,对于代码的读者/维护者来说,我的意图是非常明显的. (5认同)

Eri*_*ert 22

我的问题是:为什么他们两个(我意识到必须有一个很好的理由)

如果有充分的理由还没有向我解释.C#中的平等比较是一个混乱的混乱,并且在我对C#的设计感到遗憾的事情列表中排名第9:

http://www.informit.com/articles/article.aspx?p=2425867

在数学上,平等是最简单的等价关系,它应该遵守规则:x == x应该始终是真的,x == y应该始终是相同的y == x,x == y并且x != y应该始终是相反的,如果x == y并且y == z是真的那么x == z必须是真的.C#==Equals机制保证不会有这些属性!(幸运的是,ReferenceEquals保证所有这些.)

正如乔恩在他的回答指出,==基于编译时类型的两个操作数的布控,并.Equals(object).Equals(T)来自IEquatable<T>基于运行时类型的左操作数的调度.为什么这些调度机制中的任何一个都正确?平等不是一个有利于左手的谓词,那么为什么有些但不是所有的实现都这样做呢?

实际上我们想要的用户定义的相等是一种多方法,其中两个操作数的运行时类型具有相同的权重,但这不是C#中存在的概念.

更糟糕的是,它是非常常见的Equals并且==被赋予不同的语义 - 通常一个是引用相等而另一个是值相等.天真的开发者没有理由知道哪个是哪个,或者它们是不同的.这是一个很大的错误来源.当你意识到GetHashCode和Equals必须达成一致意见时,情况会变得更糟,但==不必如此.

如果我从头开始设计一种新语言,我出于某种疯狂的原因希望运算符重载 - 我不这样做 - 那么我会设计一个更加直接的系统.喜欢的东西:如果您实现IComparable<T>一个类型,那么你自动获得<,<=,==,!=,等,为您定义的运营商,他们正在实施,这样它们是一致的.这x<=y必须具有语义x<y || x==y和语义!(x>y),并且x == y总是相同y == x,等等.

现在,如果你的问题确实是:

我们到底是怎么进入这个神圣的混乱?

然后我在2009年写下了一些想法:

https://blogs.msdn.microsoft.com/ericlippert/2009/04/09/double-your-dispatch-double-your-fun/

TLDR是:框架设计者和语言设计者有不同的目标和不同的约束,他们有时不会在设计中考虑这些因素,以确保整个平台的一致,合理的体验.这是设计过程的失败.

什么时候==会以不同的方式超载.equals被覆盖?

除非我有一个非常不寻常的,非常好的理由,否则我永远不会这样做.当我实现算术类型时,我总是将所有运算符实现为彼此一致.