【问题标题】:Why was IEquatable T not made contravariant in T for C# 4.0?为什么 IEquatable T 没有在 C# 4.0 的 T 中实现逆变?
【发布时间】:2011-03-18 09:29:12
【问题描述】:

IEquatable 可以被声明为在 T 中是逆变的,因为它只在输入位置使用 T(或者,等价地,U 是 T 的子类型应该暗示 IEquatable 是 [a subtype of] IEquatable).

那么,为什么 BCL 团队不使用 'in' 关键字来注释它(对于 C# 4.0),就像他们对许多其他通用接口(如完全类似的 IComparable)所做的那样?

【问题讨论】:

标签: c# c#-4.0


【解决方案1】:

我认为这主要是出于哲学原因而不是技术限制——因为完全可以简单地对界面进行注释。 IEquatable<T> 用于比较相同类型的对象是否完全相等。超类的实例通常不被认为等于子类的实例。这种意义上的平等也意味着类型平等。这与IComparable<in T> 有点不同。跨不同类型定义相对排序顺序是明智的。

引用MSDN page on IEquatable<T>

实施者注意事项:

IEquatable<T>接口的类型参数替换为实现此接口的类型

这句话进一步证明了IEquatable<T> 旨在在单个具体类型的实例之间工作。

【讨论】:

  • 谢谢;我怀疑这接近事实。不过,这似乎很遗憾,因为 U 是 T 的子类型确实意味着 IEquatable T 与 U 等价……它只是不 IEquatable 到 U!换句话说,我认为注释界面没有任何不利之处......
  • 老实说,我没有看到任何 优势 使它成为逆变。说Vehicle 的实例完全等于——实际上等同于——Car 的实例是没有意义的。它们对于排序顺序可能是等效的(与 IComparable 一样),但它们永远不会真正“相等”。
  • @Khalid:考虑到理想的基类型不应该知道其派生类型的细节,它无法决定这些类型的相等性。派生类可能会添加一些属性,从而与基类提供的相等定义不同。
  • 即使没有差异,您关于实现的有效观点也适用,因为无论如何都可以在运行时将子类型传递给 Equals 方法,这仅仅是因为多态性。事实上(没有逆变注释),编译器不允许您表达运行时事实,即只要 U 是 T 的子类型, IEquatable 不可避免地会像 IEquatable 那样工作(由于多态性,仅输入参数不可避免地在逻辑上逆变)。之所以出现这种不一致,是因为 BCL 团队需要根据具体情况手动声明方差的真相...
【解决方案2】:

可继承类型通常不应实现IEquatable<T>。如果IEquatable<T> 包含GetHashCode() 方法,则可以定义IEquatable<T> 的语义来表示当检查为T 时项目应该比较相等。不幸的是,IEquatable<T>Object.Equals 绑定到相同的哈希码这一事实意味着通常IEquatable<T> 必须实现与Object.Equals 基本相同的语义。

因此,如果IEquatable<BaseClass> 的实现除了在其中调用Object.Equals 之外做了任何事情,则覆盖Object.EqualsGetHashCode() 并且不重新实现IEquatable<BaseClass> 的派生类最终会导致损坏该接口的实现; IEquatable<BaseClass> 的实现只需调用 Object.Equals 就可以正常工作,即使在这种情况下也是如此,但不会比不实现 IEquatable<T> 的类提供任何真正的优势。

鉴于可继承类首先不应该实现IEquatable<T>,协方差的概念与接口的正确实现无关。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-12-06
    • 2012-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多