c#编译器要求每当自定义类型定义operator ==时,它也必须定义!=(参见这里)。

Why?

我很好奇为什么设计人员认为这是必要的,为什么编译器不能默认为一个合理的实现操作符时,只有另一个存在。例如,Lua只允许定义相等操作符,而免费获得另一个。c#也可以做到这一点,要求你定义==或同时定义==和!=,然后自动将缺少的!=运算符编译为!(左==右)。

我知道有一些奇怪的极端情况,一些实体可能既不相等也不相等(如IEEE-754 NaN),但这些似乎是例外,而不是规则。因此,这并不能解释为什么c#编译器设计人员将例外设置为规则。

我见过一些糟糕的情况,其中定义了相等运算符,然后不等式运算符是一个复制粘贴,每个比较都反转,每个&&切换到||(你明白了吧……(a==b)通过德摩根法则展开)。这是编译器可以通过设计消除的不良实践,就像Lua一样。

注意: 运算符< > <= >=也是如此。我无法想象在哪些情况下需要用非自然的方式来定义它们。Lua只允许您定义<和<=,并通过前两者的否定自然地定义>=和>。为什么c#不做同样的事情(至少在默认情况下)?

EDIT

显然,有充分的理由允许程序员根据自己的喜好执行相等和不相等的检查。一些答案指向了这样做可能不错的案例。

然而,我问题的核心是,为什么在c#中这是强制要求的,而通常这在逻辑上是不必要的?

It is also in striking contrast to design choices for .NET interfaces like Object.Equals, IEquatable.Equals IEqualityComparer.Equals where the lack of a NotEquals counterpart shows that the framework considers !Equals() objects as unequal and that's that. Furthermore, classes like Dictionary and methods like .Contains() depend exclusively on the aforementioned interfaces and do not use the operators directly even if they are defined. In fact, when ReSharper generates equality members, it defines both == and != in terms of Equals() and even then only if the user chooses to generate operators at all. The equality operators aren't needed by the framework to understand object equality.

基本上,. net框架并不关心这些操作符,它只关心一些Equals方法。要求用户同时定义==和!=操作符的决定纯粹与语言设计有关,而与. net关心的对象语义无关。


当前回答

简而言之,强迫一致性。

'==' and '!=' are always true opposites, no matter how you define them, defined as such by their verbal definition of "equals" and "not equals." By only defining one of them, you open yourself up to an equality operator inconsistency where both '==' and '!=' can both be true or both be false for two given values. You must define both since when you elect to define one, you must also define the other appropriately so that it is blatantly clear what your definition of "equality" is. The other solution for the compiler is to only allow you to override '==' OR '!=' and leave the other as inherently negating the other. Obviously, that isn't the case with the C# compiler and I'm sure there's a valid reason for that that may be attributable strictly as a choice of simplicity.

The question you should be asking is "why do I need to override the operators?" That is a strong decision to make which requires strong reasoning. For objects, '==' and '!=' compare by reference. If you are to override them to NOT compare by reference, you are creating a general operator inconsistency that is not apparent to any other developer who would peruse that code. If you are attempting to ask the question "is the state of these two instances equivalent?," then you should implement IEquatible, define Equals() and utilize that method call.

最后,由于同样的原因,IEquatable()没有定义NotEquals():可能会导致相等运算符不一致。NotEquals()应该总是返回!通过将NotEquals()的定义开放给实现Equals()的类,您再次迫使确定相等性的一致性问题。

编辑:这只是我的理由。

其他回答

除了c#在许多方面遵从c++之外,我能想到的最好的解释是,在某些情况下,你可能想要采取一种稍微不同的方法来证明“不相等”和证明“相等”。

显然,以字符串比较为例,您可以测试是否相等,并在看到不匹配的字符时返回循环。然而,对于更复杂的问题,它可能就不那么清晰了。我想到了bloom滤镜;快速判断元素是否在集合中非常容易,但判断元素是否在集合中非常困难。虽然可以应用相同的返回技术,但代码可能没有那么漂亮。

可能只是一些他们没有想到也没有时间去做的事情。

我总是用你的方法当我超载==。然后我把它用在另一个。

你是对的,只需少量的工作,编译器就可以免费提供给我们。

这是我首先想到的:

如果测试不平等比测试平等快得多呢? 如果在某些情况下,你想同时返回false for ==和!=(也就是说,如果它们由于某种原因不能进行比较)

编程语言是对异常复杂的逻辑语句的语法重排。考虑到这一点,你能定义一个相等的情况而不定义一个不相等的情况吗?答案是否定的。如果一个物体a等于物体b,那么物体a的逆不等于b也必须成立。另一种表达方式是

如果a == b那么!(a != b)

这为语言确定对象的相等性提供了明确的能力。例如,比较NULL != NULL可能会对没有实现非相等语句的相等系统的定义产生不利影响。

现在,关于!=简单地是可替换的定义

如果!(a==b)那么a!= b

我不能反驳这一点。然而,这很可能是c#语言规范组的决定,程序员被迫显式地定义对象的相等性和非相等性

你问题中的关键词是“为什么”和“必须”。

结果是:

这样回答是因为他们设计了这样,这是真的……但不回答你的"为什么"

回答说,有时独立地覆盖这两个可能是有帮助的,是真的…但没有回答你"必须"的问题。

我认为简单的答案是,c#没有任何令人信服的理由要求你重写这两者。

该语言应该只允许您重写==,并为您提供一个默认的!=实现,即!那如果你碰巧也想重写!=,那就试试吧。

这不是一个好的决定。人类设计语言,人类并不完美,c#也不完美。耸耸肩,回答问题