C#中实现相等性的最小代码

4
在这篇文章中,Eric Lippert在第9点中指出C#有“过多的相等性”。他指出,有9或10种不同的方法或运算符可以重载以提供对象相等性。
我的第一个问题是 - 如果Object.Equals(object)方法被覆盖,编译器是否可以调用任何其他相等运算符,如==,!=,<=等,而不需要明确执行此操作的代码?
在C ++中,存在这种行为的先例。复制构造函数可以在编译器需要生成临时变量的某些地方调用。我至少95%确定这在C#中不可能发生,但它确实取决于编译器的构造方式,以及可能的边缘情况。
第二个问题是——如果编译器永远不会间接调用任何等式运算符,那么对于小型、中型甚至大型项目来说,是否可以指定仅使用 Object.Equals(object) 方法和 IEquatable 进行相等性测试,并在需要确定对象排名时使用 IComparable?换句话说,如果项目中的所有人都同意不使用其他等式运算符并且因此不必要,那么避免定义其他等式运算符是否可以?假设代码仅在项目内部使用,不会导出供第三方使用。
2个回答

6
如果重写了Object.Equals(object)方法,编译器是否可能在没有明确执行此操作的代码的情况下调用任何其他相等运算符,例如==!=<=等? C#编译器不知道Equals==在语义上是相同的。如果调用了Equals,则会调用该方法。
那么在小型、中型或大型项目中只指定使用Object.Equals(object)方法和IEquatable进行相等性测试,并且仅在需要确定对象排名时使用IComparable是否可以?换句话说,如果每个人都同意他们不会使用其他相等运算符并且因此是不必要的,那么避免定义其他相等运算符是否可以?你会遇到的危险是默认情况下会为你定义一个执行引用相等性的==运算符。你很容易遇到这样一种情况,即重载的Equals方法执行数值相等性,而==执行引用相等性,然后你意外地在数值相等但不是引用相等的事物上使用了引用相等性。这是一种容易出现错误的做法,人工代码审查难以发现。几年前,我曾经在静态分析算法上工作,以统计性地检测这种情况,我们发现在所有研究的代码库中每百万行代码有约两个实例的缺陷率。当考虑已覆盖Equals的代码库时,缺陷率明显更高!此外,请考虑成本与风险。如果您已经实现了IComparable,那么编写所有运算符的简单一行代码非常容易,并且不会出现错误并且永远不会更改。这是您将要编写的最便宜的代码。如果在编写和测试十二个微小方法的固定成本与查找和修复难以发现的错误,其中使用引用相等性而不是值相等性,则成本无限,我知道我会选择哪一个。

4
我的第一个问题是 - 如果Object.Equals(object)方法被覆盖,编译器是否可以在没有明确执行此操作的代码的情况下调用任何其他等式运算符,如==、!=、<=等?
我所知道的是不行。
第二个问题是 - 如果编译器从未间接调用任何等式运算符,那么对于小型、中型或甚至大型项目而言,指定仅使用Object.Equals(object)方法和IEquatable进行相等性测试,并且只有在需要确定对象等级时才使用IComparable,是否可以?换句话说 - 如果所有人都同意不使用它们并且因此不必要,则避免定义其他等式运算符是否可以接受?
从技术上讲,您建议的做法是可行的。但在实践中,即使我是唯一参与项目的人,我也不会信任自己遵循已经建立的规范。我还会为我进行的每个LINQ方法调用担心:这个LINQ方法如何在内部工作?它需要IEquatable吗?它使用了IComparable吗?我在这里安全吗?
如果我尝试类似于您建议的方法,我可能仍然会让我的类实现所有相关的等式接口,但是默认情况下将方法抛出NotSupportedException异常。这样,至少我会感觉有一个安全网,以防我错误地使用了错误的方法,或者如果我使用依赖于不同等式接口的库方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接