39

IComparableとジェネリックの両方を実装する必要がありIComparable<T>ますか? そのうちの 1 つだけを実装する場合、何か制限はありますか?

4

3 に答える 3

24

はい、両方を実装する必要があります。

一方を実装すると、もう一方に依存するコードは失敗します。

IComparableどちらか一方または両方を使用しないコードがたくさんあるIComparable<T>ので、両方を実装すると、コードがそのようなコードで機能することが保証されます。

于 2011-09-04T18:31:51.247 に答える
23

どちらか一方の実装のみに依存するコレクションやその他のクラスがあるため、両方を実装する必要があるという 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> インターフェイスを実装する方法

于 2013-05-10T23:15:44.823 に答える
4

IEquatable<T> は通常、封印されていないクラスによって実装されるべきではありませんが、そのような派生は、実装が単に Object.Equals を呼び出す場合を除き (その場合は無意味です)、継承で奇妙に動作するため、逆の状況がジェネリック IComparable<T で発生します。 >。Object.Equals と IEquatable<T> のセマンティクスは、IEquatable<T> が定義されている場合は常に、その動作が Object.Equals の動作を反映する必要があることを意味します (より高速でボクシングを回避する可能性は別として)。DerivedFoo 型と見なされたときに等しいと見なされる DerivedFoo 型の 2 つのオブジェクトは、Foo 型と見なされたときにも同等である必要があり、その逆も同様です。一方、タイプ DerivedFoo と見なされたときにランクが等しくないタイプ DerivedFoo の 2 つのオブジェクトが、タイプ Foo と見なされたときにランクが等しくなる可能性は十分にあります。

たとえば、ScheduledTime (DateTime 型) フィールドと ScheduledAction (MethodInvoker 型) フィールドを含む SchedulerEvent クラスがあるとします。このクラスには、SchedulerEventWithMessage (string 型の Message フィールドを追加する) サブタイプと SchedulerEventWithGong (Double 型の GongVolume フィールドを追加する) のサブタイプが含まれます。SchedulerEvent クラスには、ScheduledTime による自然な順序付けがありますが、互いに相対的に順序付けされていないイベントが等しくない可能性は十分にあります。SchedulerEventWithMessage クラスと SchedulerEventWithGong クラスにも自然な順序がありますが、SchedulerEvent クラスのアイテムと比較するとそうではありません。

2 つの 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 のメンバーの基礎のみと比較することは有用であると主張する人もいるかもしれません。 SchedulerEventWithMessage または SchedulerEventWithGong への接続は、Message または GongVolume プロパティをチェックしません。確かに、これらは IEquatable<T> メソッドの有用なセマンティクスであり、私はそのようなセマンティクスを好みますが、1 つの問題があります: Comparer<T>.Default.GetHashCode(T) は、これにより、IEquatable<T> が異なる型 T で動作を変える能力が大幅に制限されます。

于 2011-09-13T04:29:43.870 に答える