web-dev-qa-db-ja.com

IEnumerableとIEnumerable <T>の違いは?

IEnumerableIEnumerable<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>

これらについても知りたいです。

51
Nawaz

基本的に、.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を行うことに注意してください。これは、そうするのがタイプセーフではないからです...あらゆる値をobjectIListに(ボックス化する可能性がある)変換するため、ジェネリックイテレータは非ジェネリックイテレータと見なすことができます。 ICollection値をコレクションに追加することができます。そして、文字列をIList<int>に(たとえば)追加することは意味がありません。

編集:IEnumerable<T>が必要な理由は、タイプセーフな方法で反復し、その情報を伝達できるようにするためです。私がIEnumerable<string>を返す場合、そこから返されるすべてが文字列参照またはnullであると安全に想定できることをご存じでしょう。 IEnumerableforeachプロパティがCurrentのプロパティであるため、IEnumeratorを使用すると、シーケンスから返された各要素を効果的にキャストする必要があります_はobjectタイプです。なぜstillが必要なのかについては、IEnumerableが必要です-古いインターフェイスは基本的に消えないからです。それを使用している既存のコードが多すぎます。

IEnumerable<T>IEnumerableを拡張しないことは可能でしたが、IEnumerable<T>を利用したいコードはIEnumerableを受け入れるメソッドを呼び出すことができませんでした-.NET 1.1と1.0からは、そのようなメソッドがたくさんありました。

58
Jon Skeet

一方はObject型のオブジェクトを返し、もう一方はT型のオブジェクトを返します。

7
Edwin Buck

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
2
asawyer

ループを反復する間、IEnumeratorは状態を維持します。カーソル位置を記憶し、IEnumerableは記憶しません。

1
user2105566