38

これは古い質問かもしれません: なぜ はIEnumerable<T>から継承するのIEnumerableですか?

これが .NET のやり方ですが、少し問題が生じます。クラスimplementsを書くたびにIEumerable<T>、2つのGetEnumerator()関数を書く必要があります.1つはforともう1つはIEnumerable<T>forIEnumerableです。

また、IList<T>IList から継承しません。

IEnumerable<T>なぜ他の方法で設計されているのかわかりません。

4

4 に答える 4

50

馬の口から直接 (Hejlsberg):

理想的には、すべてのジェネリック コレクション インターフェイス ( ICollection<T>、 などIList<T>) は、ジェネリック インターフェイス インスタンスをジェネリック コードと非ジェネリック コードの両方で使用できるように、対応する非ジェネリック インターフェイスから継承します。たとえば、IList<T>を期待するコードに を渡すことができれば便利ですIList

判明したように、これが可能な唯一のジェネリック インターフェイスは です。これはIEnumerable<T>、 のみIEnumerable<T>が反変であるためです: ではIEnumerable<T>、型パラメーター T は「出力」位置 (戻り値) でのみ使用され、「入力」位置 (パラメーター)。ICollection<T>入力位置と出力位置の両方で TをIList<T>使用するため、これらのインターフェイスは不変です。(余談ですが、T が入力位置でのみ使用された場合、それらは反変になりますが、ここではあまり重要ではありません。)

<...中略...>

だから、あなたの質問に答えるために、IEnumerable<T>継承IEnumerableできるからです!:-)

于 2008-10-21T12:52:57.340 に答える
17

の答えIEnumerableは、「型の安全性に影響を与えずにできるから」です。

IEnumerableは「読み取り専用」インターフェースです。したがって、ジェネリック形式が非ジェネリック形式よりも具体的であることは問題ではありません。両方を実装しても何も壊れません。IEnumerator.Currentを返しますがobject、これIEnumerator<T>.Currentはボクシングを意味するかもしれませんが、Tいつでも合法的に に変換できるため、問題ありません。object

IList<T>これをand と比較してくださいIList- あなたは を呼び出すことができますがAdd(object)、それは特定のもの (実際以外のもの)IListに対して無効である可能性があります。IList<T>IList<object>

Brad Abram のブログに、まさにこの質問に関するAnders の回答が掲載されています。

于 2008-10-21T12:52:13.193 に答える
3

下位互換性のためです。通常の IEnumerable を期待する .Net 1.1 関数を呼び出す場合は、汎用の IEnumerable を渡すことができます。

幸いなことに、汎用の IEnumerator は古いスタイルの IEnumerator を継承しています。

私は通常、列挙子を返すプライベート メソッドを実装し、それを古いスタイルと新しいスタイルの両方の GetEnumerator メソッドに渡します。

    private IEnumerator<string> Enumerator() {
        // ...
    }

    public IEnumerator<string> GetEnumerator() {
        return Enumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
        return Enumerator();
    }
于 2008-10-21T12:53:36.060 に答える
2

これは、ジェネリックをサポートしないクラスで動作するようにするためです。さらに、.NET ジェネリックでは、IList<long> を IList<int> としてキャストするようなことはできないため、固定の基本クラスまたはインターフェイスが必要な場合は、非ジェネリック バージョンのインターフェイスが非常に役立ちます。

于 2008-10-21T12:52:56.640 に答える