なぜIEnumerable< T> IEnumerableから継承しますか?
-
03-07-2019 - |
質問
これは古い質問かもしれません:なぜ IEnumerable< T>
は IEnumerable
を継承するのですか?
これは.NETの動作ですが、少し面倒です。クラスを書くたびに IEumerable< T>
を実装するたびに、 IEnumerable< T>
と IEnumerable
のもう1つ。
そして、 IList< T>
はIListを継承しません。
IEnumerable< T>
が他の方法で設計されている理由がわかりません。
解決
馬の口からの直線(Hejlsberg) :
理想的には、すべてのジェネリックコレクションインターフェイス(例:
ICollection< T>
、IList< T>
)は、ジェネリックインターフェイスインスタンスができるように、非ジェネリックの対応物から継承します。汎用コードと非汎用コードの両方で使用されます。たとえば、IList< T>
をIList
を予期するコードに渡すことができれば便利です。結局のところ、これが可能な唯一の汎用インターフェイスは
IEnumerable< T>
です。これは、IEnumerable< T>
のみが反変であるためです:In < code> IEnumerable&lt; T&gt; 、型パラメーターTは&quot; output&quot;でのみ使用されます。 「入力」ではなく、位置(戻り値)。位置(パラメーター)。ICollection&lt; T&gt;
およびIList&lt; T&gt;
は、入力位置と出力位置の両方でTを使用するため、これらのインターフェイスは不変です。 (余談ですが、Tが入力位置でのみ使用された場合、それらは反変でしたが、それは実際にはここでは重要ではありません。)&lt; ... snip ...&gt;
つまり、質問に答えるために、 IEnumerable&lt; T&gt;
は IEnumerable
を継承しています。 :-)
他のヒント
IEnumerable
の答えは、「型の安全性に影響を与えずにできるから」です。
IEnumerable
は「読み取り専用」ですインターフェース-ジェネリック形式が非ジェネリック形式よりも具体的であることは重要ではありません。両方を実装しても何も壊れません。 IEnumerator.Current
は object
を返しますが、 IEnumerator&lt; T&gt; .Current
は T
を返します。常に合法的に object
に変換しますが、ボクシングを意味する場合があります。
これを IList&lt; T&gt;
および IList
と比較します- IList
で Add(object)
を呼び出すことができます>、それは特定の IList&lt; T&gt;
(実際には IList&lt; object&gt;
以外のもの)では無効かもしれません。
Brad Abramの Andersの回答をブログに掲載このまさに質問。
下位互換性のためです。バニラIEnumerableを期待する.Net 1.1関数を呼び出す場合、ジェネリックIEnumerableを渡すことができます。
Luckillyは、一般的なIEnumeratorが古いスタイルのIEnumeratorから継承します
通常、列挙子を返すプライベートメソッドを実装し、古いスタイルと新しいスタイルの両方のGetEnumeratorメソッドに渡します。
private IEnumerator<string> Enumerator() {
// ...
}
public IEnumerator<string> GetEnumerator() {
return Enumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return Enumerator();
}
これは、ジェネリックをサポートしないクラスで動作するようにするためです。さらに、.NETジェネリックでは、キャストIList&lt; long&gt;などを実行できません。 IList&lt; int&gt;のように、固定の基本クラスまたはインターフェイスが必要な場合、インターフェイスの非ジェネリックバージョンは非常に便利です。