我应该同时实施IComparable
和通用IComparable<T>
吗?如果我只执行其中一个,是否有任何限制?
答案 0 :(得分:21)
是的,你应该实现这两个。
如果实现一个,任何依赖另一个的代码都将失败。
有很多代码使用IComparable
或IComparable<T>
,但不能同时使用这两种代码,因此实现这两项代码时,请确保您的代码可以使用此类代码。
答案 1 :(得分:21)
Oded是正确的,你应该实现它们,因为有集合和其他类只依赖于其中一个实现。
但那里有一个技巧:IComparable&lt; T&gt;不应该抛出异常,而IComparable应该。当实现IComparable&lt; T&gt;时您负责确保T的所有实例可以相互比较。这也包括null(将null视为小于T的所有非null实例,你会没事的。)
但是,一般的IComparable接受System.Object并且您无法保证所有可想到的对象都可以与T的实例进行比较。因此,如果您将非T实例传递给IComparable,只需抛出System.ArgumentException。否则,将呼叫路由到IComparable&lt; T&gt;实施
以下是示例:
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时应该注意的副作用的广泛分析&lt; T&gt;:How to Implement IComparable<T> Interface in Base and Derived Classes
答案 2 :(得分:4)
虽然IEquatable&lt; T&gt;通常不应该通过未密封的类来实现,因为这种推导将继承奇怪的继承,除非实现简单地调用Object.Equals(在这种情况下它将是毫无意义的),相反的情况出现在通用IComparable&lt; T&gt;中。 Object.Equals和IEquatable&lt; T&gt;的语义。暗示每当IEquatable&lt; T&gt;时在定义时,它的行为应该反映Object.Equals的行为(除了可能更快并且避免装箱)。当被视为类型为DerivedFoo时,DerivedFoo类型的两个对象比较相等也应该在被视为Foo类型的对象时比较相等,反之亦然。另一方面,当被视为DerivedFoo类型时,DerivedFoo类型的两个对象完全有可能在被视为类型Foo时排名相同。确保这一点的唯一方法是使用IComparable&lt; T&gt;。
例如,假设有一个类SchedulerEvent,它包含ScheduledTime(类型为DateTime)和ScheduledAction(类型为MethodInvoker)字段。该类包括子类型SchedulerEventWithMessage(它添加一个string类型的Message字段)和SchedulerEventWithGong(它添加一个Double类型的GongVolume字段)。 SchedulerEvent类具有ScheduledTime的自然顺序,但是相对于彼此无序的事件完全可能是不相等的。 SchedulerEventWithMessage和SchedulerEventWithGong类之间也有自然的排序,但与SchedulerEvent类的项比较时不会。
假设有一个SchedulerEventWithMessage事件X和Y同时安排,但X.Message是“aardvark”而Y.Message是“zymurgy”。 ((IComparable&lt; SchedulerEvent&gt;)X).CompareTo(Y)应该报告零(因为事件有相同的时间)但是((IComparable&lt; SchedulerEventWithMessage&gt;)X).CompareTo(Y)应该返回一个负数(因为“aardvark”)在“zymurgy”之前排序。如果类没有这样做,那么很难或不可能一致地命令包含SchedulerEventWithMessage和SchedulerEventWithGong对象混合的列表。
顺便提一下,人们可能会争辩说,拥有IEquatable&lt; T&gt;的语义会很有用。比较对象只是类型T的成员的基础,所以例如IEquatable&LT; SchedulerEvent&GT;会检查ScheduledTime和ScheduledAction是否相等,但即使应用于SchedulerEventWithMessage或SchedulerEventWithGong也不会检查Message或GongVolume属性。实际上,对于IEquatable&lt; T&gt;而言,那些将是有用的语义。方法,我倾向于这样的语义,但是对于一个问题:Comparer&lt; T&gt; .Default.GetHashCode(T)总是调用相同的函数Object.GetHashCode()而不管类型T.这极大地限制了IEquatable&lt; T&gt;的能力。改变不同类型的行为T.