C# 中相等性的最少代码

Minimal code for equality in C#

在此 article 中,Eric Lippert 在第 9 点中建议 C# 具有 "too much equality"。他指出,有 9 或 10 种不同的方法或运算符可以重载以提供对象相等性。

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

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

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

假定代码仅供项目内部使用,不会导出供第三方使用。

My first question is - if the Object.Equals(object) method is overridden, is it possible for the compiler to call any of the other equality operators like ==, !=, <=, etc. without code that expressly performs this operation?

据我所知没有。

The second question is - if the compiler will never call any of the equality operators indirectly, then would it be ok for a small, medium, or even large project to specify that only the Object.Equals(object) method and IEquatable be used for equality testing, and IComparable used if the type will be used for sorting or other times when determining the rank of the objects is needed? In other words - is it ok to avoid defining the other equality operators if everyone on the project agrees they won't be used and are therefore unnecessary?

从技术上讲,您的建议是可行的。但在实践中,我什至不相信自己会遵守既定规范,即使我是唯一一个从事该项目的人。我还会发现自己对我进行的每个 LINQ 方法调用都感到担忧:这个 LINQ 方法在幕后是如何工作的?需要IEquatable吗?它使用IComparable吗?我在这里安全吗?

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

if the Object.Equals(object) method is overridden, is it possible for the compiler to call any of the other equality operators like ==, !=, <=, etc. without code that expressly performs this operation?

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

then would it be ok for a small, medium, or even large project to specify that only the Object.Equals(object) method and IEquatable be used for equality testing, and IComparable used if the type will be used for sorting or other times when determining the rank of the objects is needed? In other words - is it ok to avoid defining the other equality operators if everyone on the project agrees they won't be used and are therefore unnecessary?

你 运行 进入这里的危险是你得到一个为你定义的 == 运算符,默认情况下引用相等。您很容易陷入这样一种情况,即重载的 Equals 方法执行值相等而 == 执行引用相等,然后您不小心对值相等的非引用相等的事物使用了引用相等。这是一种容易出错的做法,人工代码审查很难发现。

几年前,我研究了一种静态分析算法来统计检测这种情况,我们发现在我们研究的所有代码库中,每百万行代码的缺陷率约为两个实例.当仅考虑在某处被覆盖的代码库 Equals 时,缺陷率显然要高得多!

此外,考虑成本与风险。如果你已经有了 IComparable 的实现,那么编写所有的运算符就是简单的单行代码,不会有错误,也永远不会改变。这是您编写的最便宜的代码。如果要在编写和测试十几个小方法的固定成本与查找和修复使用引用相等而不是值相等的难以发现的错误之间进行选择,我知道我会选择哪个。