繁体   English   中英

IComparable和IComparable <T>

[英]IComparable and IComparable<T>

我应该同时实现IComparable和泛型IComparable<T>吗? 如果仅实现其中之一,是否有任何限制?

Oded是正确的,您应该同时实现这两者,因为有些集合和其他类仅依赖于其中一种实现。

但是,这里有一个窍门:IComparable <T>不应引发异常,而IComparable则应引发异常。 在实现IComparable <T>时,您负责确保可以将T的所有实例相互比较。 这也包括null(将null处理为小于T的所有非null实例,那么就可以了)。

但是,常规IComparable接受System.Object,并且不能保证所有可想到的对象都可以与T的实例进行比较。因此,如果将非T实例传递给IComparable,则只需抛出System.ArgumentException。 否则,将调用路由到IComparable <T>实现。

这是示例:

public class Piano : IComparable<Piano>, IComparable
{
    public int CompareTo(Piano other) { ... }
    ...
    public int CompareTo(object obj)
    {

        if (obj != null && !(obj is Piano))
            throw new ArgumentException("Object must be of type Piano.");

        return CompareTo(obj as Piano);

    }
}

此示例是更长篇文章的一部分,其中包含对副作用的广泛分析,在实现IComparable <T>时应注意: 在基类和派生类中如何实现IComparable <T>接口

是的,您应该同时实现。

如果实现一个,则任何依赖于另一个的代码都将失败。

有很多使用IComparableIComparable<T>的代码,但不能同时使用两者,因此同时实现这两个代码可确保您的代码将与此类代码一起使用。

尽管IEquatable <T>通常不应由未密封的类实现,因为除非实现只调用Object.Equals(在这种情况下将是毫无意义的),否则这种派生会在继承中扮演奇怪的角色,而与之相反的情况是通用IComparable <T >。 Object.Equals和IEquatable <T>的语义意味着,每当定义IEquatable <T>时,其行为都应与Object.Equals相同(除了可能更快并且避免装箱)。 当被视为DerivedFoo类型时比较相同的两个DerivedFoo类型对象也应在被视为Foo类型对象时比较相等,反之亦然。 另一方面,完全有可能两个DerivedFoo类型的对象在被视为DerivedFoo类型时排名不相等,而在被视为Foo类型时也应排名相等。 确保这一点的唯一方法是使用IComparable <T>。

例如,假设有一个SchedulerEvent类,它包含ScheduledTime(DateTime类型)和ScheduledAction(MethodInvoker类型)字段。 该类包括子类型SchedulerEventWithMessage(添加了字符串类型的Message字段)和SchedulerEventWithGong(添加了Double类型的GongVolume字段)。 SchedulerEvent类按ScheduledTime具有自然排序,但相对于彼此无序的事件完全不相等是完全可能的。 SchedulerEventWithMessage和SchedulerEventWithGong类之间也具有自然顺序,但与SchedulerEvent类的项目相比则没有。

假设有两个SchedulerEventWithMessage事件X和Y分别安排在同一时间,但X.Message是“ aardvark”,而Y.Message是“ zymurgy”。 ((IComparable <SchedulerEvent>)X).CompareTo(Y)应该报告零(因为事件具有相等的时间),但是(((IComparable <SchedulerEventWithMessage>)X).CompareTo(Y)应该返回负数(因为“ aardvark”在“ zymurgy”之前排序)。 如果该类不以这种方式运行,则很难或不可能一致地对包含SchedulerEventWithMessage和SchedulerEventWithGong对象的混合物的列表进行排序。

顺便说一句,可能有人认为仅使IEquatable <T>的语义仅基于类型T的成员比较对象就很有用,因此IEquatable <SchedulerEvent>会检查ScheduledTime和ScheduledAction是否相等,即使应用时也是如此。到SchedulerEventWithMessage或SchedulerEventWithGong不会检查Message或GongVolume属性。 确实,那些对于IEquatable <T>方法将是有用的语义,而我更喜欢这种语义,但是对于一个问题:Comparer <T> .Default.GetHashCode(T)始终调用相同的函数Object.GetHashCode()而不管类型T。这极大地限制了IEquatable <T>随不同类型T改变其行为的能力。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM