任何人对IEquatable<T>IComparable<T>是否通常应要求Tsealed(如果是class)有任何意见?

因为我正在编写一组旨在帮助实现不可变类的基类,所以我想到了这个问题。基类打算提供的部分功能是自动实现相等性比较(使用类的字段以及可以应用于字段以控制相等性比较的属性)。完成后应该会很不错-我正在使用表达式树为每个T动态创建一个已编译的比较函数,因此比较函数应该非常接近常规相等比较函数的性能。 (我使用的是基于System.Type的不可变字典,并进行了双重检查锁定,以合理的方式存储生成的比较函数)

但是出现的一件事是,用于检查成员字段是否相等的功能。我最初的目的是检查每个成员字段的类型(我将其称为X)是否实现IEquatable<X>。但是,经过一番思考,除非Xsealed,否则我认为这是不安全的。原因是如果X不是sealed,我不确定X是否适当地将相等性检查委托(delegate)给X上的虚拟方法,从而允许子类型重写相等性比较。

然后,这提出了一个更笼统的问题-如果类型不是密封的,那么它真的应该全部实现这些接口(interface)吗?我认为不会,因为我认为接口(interface)协定是在两种X类型之间进行比较,而不是两种可能不是X的类型(尽管它们当然必须是X或子类型)。

你们有什么感想?对于未密封的类,应避免使用IEquatable<T>IComparable<T>吗? (这也让我想知道是否有fxcop规则)

我当前的想法是让生成的比较函数仅在IEquatable<T>T的成员字段上使用sealed,并且即使Object.Equals(Object obj)实现T,也可以在未密封T的情况下使用虚拟IEquatable<T>,因为该字段可能存储了T的子类型,因此我怀疑IEquatable<T>的大多数实现都是为继承而适当设计的。

最佳答案

我一直在考虑这个问题,经过一番考虑之后,我同意实现IEquatable<T>IComparable<T>只能在密封类型上完成。

我来回走了一段时间,但随后想到了以下测试。以下情况在什么情况下应返回false?恕我直言,2个对象相等或不相等。

public void EqualitySanityCheck<T>(T left, T right) where T : IEquatable<T> {
  var equals1 = left.Equals(right);
  var equals2 = ((IEqutable<T>)left).Equals(right);
  Assert.AreEqual(equals1,equals2);
}

假定比较器为等效类型,则给定对象上IEquatable<T>的结果应具有与Object.Equals相同的行为。在对象层次结构中两次实现IEquatable<T>可以并且有两种隐含的方式在系统中表达相等性。很容易想到IEquatable<T>Object.Equals会有所不同的任何情况,因为存在多个IEquatable<T>实现,但只有一个Object.Equals。因此,以上操作将失败并在您的代码中造成一些困惑。

有人可能会争辩说,在对象层次结构的较高位置实现IEquatable<T>是有效的,因为您想比较对象属性的子集。在这种情况下,您应该选择专门用于比较这些属性的IEqualityComparer<T>

10-08 04:36