C#中相等的最小代码

在本文中 ,Eric Lippert在第9点建议C#具有“太多平等”。 他指出,有9或10种不同的方法或运算符可以重载以提供对象相等性。

我的第一个问题是 – 如果重写了Object.Equals(object)方法,编译器是否可以调用任何其他相等运算符,如==,!=,<=等,而无需明确执行此操作的代码?

在C ++中,这种行为有先例。 编译器可以在需要生成临时变量的某些位置调用复制构造函数。 我至少95%肯定这不会发生在C#中,但它实际上取决于编译器的构造方式以及边缘情况。

第二个问题是 – 如果编译器永远不会间接调用任何相等运算符,那么小型,中型甚至大型项目是否可以指定只使用Object.Equals(object)方法和IEquatable来实现如果类型将用于排序或其他时间确定对象的等级需要使用等式测试和IComparable吗? 换句话说 – 如果项目中的每个人都同意他们不会被使用并因此是不必要的,那么可以避免定义其他相等运算符吗?

假设代码仅在项目中使用,不会导出供第三方使用。

如果重写了Object.Equals(object)方法,编译器是否可以调用任何其他相等的运算符,如==!=<=等,而没有明确执行此操作的代码?

C#编译器不知道Equals==在语义上是相同的。 如果你调用Equals那么将调用该方法。

那么小型,中型甚至大型项目是否可以指定只使用Object.Equals(object)方法和IEquatable进行相等性测试,如果类型将用于排序或其他时候使用IComparable需要确定对象的等级吗? 换句话说 - 如果项目中的每个人都同意他们不会被使用并因此是不必要的,那么可以避免定义其他相等运算符吗?

您遇到的危险是您为自己定义的==运算符默认情况下会引用相等性。 您可以很容易地在一个重载的Equals方法确实值相等并且==确实引用相等的情况下结束,然后您不小心在值相等的非引用相等的事物上使用引用相等。 这是一种容易出错的做法,人工代码审查很难发现。

几年前,我研究了一种静态分析算法来统计检测这种情况,我们在所研究的所有代码库中发现了每百万行代码大约两个实例的缺陷率。 当只考虑具有某些被覆盖的Equals代码库时,缺陷率明显更高!

此外,考虑成本与风险。 如果你已经有了IComparable实现,那么编写所有运算符都是微不足道的单行程序,它们不会有bug并且永远不会被更改。 这是你要编写的最便宜的代码。 如果在编写和测试十几种微小方法的固定成本与发现和修复难以看到的错误的无限成本之间做出选择,其中使用引用相等而不是值相等,我知道我会选择哪一个。

我的第一个问题是 – 如果重写了Object.Equals(object)方法,编译器是否可以调用任何其他相等运算符,如==,!=,<=等,而无需明确执行此操作的代码?

从来没听说过。

第二个问题是 – 如果编译器永远不会间接调用任何相等运算符,那么小型,中型甚至大型项目是否可以指定只使用Object.Equals(object)方法和IEquatable来实现如果类型将用于排序或其他时间确定对象的等级需要使用等式测试和IComparable吗? 换句话说 – 如果项目中的每个人都同意他们不会被使用并因此是不必要的,那么可以避免定义其他相等运算符吗?

从技术上讲,你的建议是可能的。 但在实践中,即使我是唯一一个参与该项目的人,我甚至不相信自己能够遵循既定的规范。 我也会发现自己担心我所做的每一个LINQ方法调用:这个LINQ方法如何工作? 它需要IEquatable吗? 它是否使用IComparable ? 我在这里安全吗?

如果我尝试对你建议的方法采用类似的方法,我可能仍然会让我的类实现所有相关的相等接口,但是默认情况下这些方法会抛出一个NotSupportedExceptionexception。 这样,至少我觉得我有一个安全网,以防我错误地使用错误的方法,或者我使用依赖于不同的相等接口的库方法。