CSharp - c#我们为什么一定要同时定义了==和!=

  显示原文与译文双语对照的内容

C# 编译器要求每当自定义类型定义运算符 == 时,它也必须定义 != ( 请参见这里的 ) 。

为什么?

我很想知道,为什么设计者的思想有必要及编译器为什么不能默认为一个合理的实现对操作者当仅存在在其他的任何一个。 例如Lua允许你只定义相等运算符,而你可以得到另一个。 C# 也可以要求你定义==或者==和!=,然后自动编译缺少的!= 运算符作为 !(left == right)

我知道有些奇怪的角落情况,有些实体可能既不相等也不不相等,但它们看起来像例外,而不是规则。 所以这并不解释为什么 C# 编译器设计器将异常作为规则。

我见过做工较差的情况下,在不等运算符是一个等号运算符被定义,那么在与每一位比较反转,而每个 && copy-paste切换到非 || ( 你一定看出来了- - 基本( a==b ) 扩展了的规则。 编译器可以通过设计消除这种情况,这是不好的做法,就像使用Lua一样。

注意:运算符 <> <=> = 相同。 我无法想象你需要用自然的方式定义这些。 Lua允许你只定义 <和 <=,并通过先行对象negation否定naturally自然地定义> = 和> 。 为什么 C# 在默认情况下不执行相同的( 至少'')?

编辑

显然有一些合理的理由允许程序员实现检查相等和不等式,然而他们喜欢。 一些答案指向可能很好的情况。

不过,我的问题就是为什么要被强行 C# 当通常中所需的核心并不是逻辑上有必要?

它一样也在为. NET 鲜明对比来设计选择接口( 如 Object.EqualsIEquatable.EqualsIEqualityComparer.Equals 缺乏哪一个 NotEquals 表明,该框架考虑 Equals() 对象为不等那么结论就是后起之秀。! 此外,像 Dictionary.Contains() 这样的类完全依赖于前面提到的接口,即使它们是定义的,也不直接使用操作符。 在all,事实上,当ReSharper生成相等的成员,它定义了两个 ==!=Equals() 方面,但即便如此,只有在用户选择生成 operators. 框架不需要相等运算符来理解对象相等性。

基本上,.NET 框架不关心这些操作符,它只关心一些 Equals 方法。 需要用户同时定义==和!= 运算符的决策与语言设计相关,而不是对象语义,这与. NET 有关。

时间:

可能是因为有人需要实现three-valued逻辑( 例如 。 null ) 。在类似于- ANSI标准SQL的情况下,运算符不能仅仅根据输入而被求反。

你可以使用以下情况:


var a = SomeObject();

a == true 返回 falsea == false 也返回 false

除此之外 C# 乐于参阅 C++ 在很多地方,我能想到的最好的解释是,在某些情况下你可能希望采取一种不同的方法来证明"不相等"比将它的证明"相等"稍 。

显然,通过字符串比较,你可以在看到不匹配字符时测试是否有相等和 return 。 然而,对于更复杂的问题,可能没有那么清晰。 布隆过滤器脑海中闪现,他非常轻松地快速告诉如果元素是不是在集合中,但很难判断该元素是处于集合中。 虽然同样的return 技术可以应用,但代码可能不如。

如果你看看实现的重载中==和!=的源,它们通常都不会实现!=. NET 作为!( 左==右) 。 他们用否定逻辑实现了完全( 像 == ) 。 例如DateTime实现==作为


return d1.InternalTicks == d2.InternalTicks;

和!= 作为


return d1.InternalTicks!= d2.InternalTicks;

如果( 或者编译器是否隐式地执行了) 要实现!=

 
return!(d1==d2);

 

然后在你的类引用的内容中假设==和!=的内部实现。 避免这种假设可能是他们决策背后的哲学。

这就是我的想法:

  • 如果测试不等式is比测试相等快得多
  • == 相关和 != ( 要是在某些情况下你想返回 false都行, 如果由于某种原因无法进行比较

你问题中的关键词是"的原因"和"磅必须"。

结果:

答案是这样的,因为他们设计成这样,是真的。。 但不回答问题的"为何"部分。

出答案,测试可能有时候会帮助可以替代这两种独立工作,是真的- - 但不回答问题的"必须必须"部分。

我认为简单的答复是,有任何令人信服的理由不是 C# 需要用户替代两者。

语言应该允许你只覆盖 ==,并为你提供 !=的默认实现,即 ! 。 如果你碰巧想要覆盖 !=,那么就可以。

这不是一个好的决定。 人类设计语言,人类不是完美的,C# 不是完美的。 Shrug和 Q.E. 。

嗯,这可能只是一个设计选项,但就像你所说,x!= y 不必与 !(x == y) 相同。 通过不添加默认实现,你肯定无法忘记实现特定的实现。 如果它真的和你说的一样简单,你可以使用另一个。 我看不出这是'练习差'。

C# 和Lua之间可能还有其他一些区别。。

在这里添加精彩的答案:

考虑会发生什么在调试器中,当你尝试单步执行和结束立刻出现在 ==!= 运算符运算符来代替! 讨论困惑 !

有意义的是,CLR允许你自由地忽略一个或者多个操作符- 因为它必须使用多种语言。 但是 C# 有大量的示例不公开CLR特性( ref 返回和局部变量,例如),并且大量实现了不在CLR本身中实现特性的示例( 例如: usinglockforeach 等) 。

...