IEnumerable
とIEnumerable<T>
の違いは何ですか?
私はこれらの両方のインターフェースを実装する多くのフレームワーククラスを見てきました。したがって、両方を実装することで得られる利点を知りたいのですが。
それらがどのように定義されているか見てください:
public interface IEnumerable
{
[DispId(-4)]
IEnumerator GetEnumerator();
}
public interface IEnumerable<T> : IEnumerable
{
IEnumerator<T> GetEnumerator();
}
ご覧のように、IEnumerable<T>
はIEnumerable
から派生します。つまり、IEnumerable
が持つもの、IEnumerable<T>
は継承します。それでは、IEnumerable<T>
だけでなく、両方を実装するのはなぜですか。 IEnumerable<T>
の実装では不十分ですか?
同様に、他にも同様のペアがあります。
IList
およびIList<T>
ICollection
およびICollection<T>
これらについても知りたいです。
基本的に、.NET 1.0および1.1では、非ジェネリックインターフェイスが最初に登場しました。次に.NET 2.0が登場したとき、一般的な同等のものが登場しました。ジェネリックが.NET 1.0にしたのであれば、人生はずっと単純だったでしょう:)
「両方」の代わりに「のみ」IEnumerable<T>
を実装することに関しては、基本的にhaveの両方を実装し、両方ともパラメータなしのGetEnumerator
方法。 IEnumerator<T>
もIEnumerator
を拡張するため、通常は次のようになります。
public IEnumerator<T> GetEnumerator()
{
// Return real iterator
}
// Explicit implementation of nongeneric interface
IEnumerator IEnumerable.GetEnumerator()
{
// Delegate to the generic implementation
return GetEnumerator();
}
一方、C#2で導入されたイテレータブロック(yield return
などを使用)では、幸いなことに、これらを完全に手動で実装する必要はほとんどありません。上記のようなものを記述し、GetEnumerator
メソッドでyield return
を使用する必要がある場合があります。
IList<T>
はnot拡張IList
を行い、ICollection<T>
はnot拡張ICollection
を行うことに注意してください。これは、そうするのがタイプセーフではないからです...あらゆる値をobject
、IList
に(ボックス化する可能性がある)変換するため、ジェネリックイテレータは非ジェネリックイテレータと見なすことができます。 ICollection
値をコレクションに追加することができます。そして、文字列をIList<int>
に(たとえば)追加することは意味がありません。
編集:IEnumerable<T>
が必要な理由は、タイプセーフな方法で反復し、その情報を伝達できるようにするためです。私がIEnumerable<string>
を返す場合、そこから返されるすべてが文字列参照またはnullであると安全に想定できることをご存じでしょう。 IEnumerable
のforeach
プロパティがCurrent
のプロパティであるため、IEnumerator
を使用すると、シーケンスから返された各要素を効果的にキャストする必要があります_はobject
タイプです。なぜstillが必要なのかについては、IEnumerable
が必要です-古いインターフェイスは基本的に消えないからです。それを使用している既存のコードが多すぎます。
IEnumerable<T>
がIEnumerable
を拡張しないことは可能でしたが、IEnumerable<T>
を利用したいコードはIEnumerable
を受け入れるメソッドを呼び出すことができませんでした-.NET 1.1と1.0からは、そのようなメソッドがたくさんありました。
一方はObject型のオブジェクトを返し、もう一方はT型のオブジェクトを返します。
IEnumerable <T>がIEnumerableを実装しているにも関わらず、両方がクラスを定義している理由については、その必要はありませんが、自己文書化でサブインターフェイスを一覧表示するのはいいことです。検討する
interface IA { }
interface IB : IA { }
class A : IB {} // legal, IB implements IA
class B : IA, IB {} // also legal, possible more clear on intent
ループを反復する間、IEnumeratorは状態を維持します。カーソル位置を記憶し、IEnumerableは記憶しません。