IEnumerableとArray、IList、Listの違いは何ですか?


91

違いは何だIEnumerableとはArray

違いは何だIListとはList

これらは同じ機能を持っているようです。

回答:


101

IEnumerableは、最小限の「反復可能な」機能のみを提供します。シーケンスをトラバースすることはできますが、それだけです。これには欠点があります-たとえば、IEnumerableを使用して要素をカウントしたり、n番目の要素を取得したりすることは非常に非効率的です-しかし、これには利点もあります-たとえば、IEnumerableは、素数のシーケンスのような無限のシーケンスである可能性があります。

配列は、ランダムアクセスの固定サイズのコレクションです(つまり、それにインデックスを付けることができます)。

リストは、ランダムなアクセスが可能な可変サイズのコレクションです(つまり、要素を追加および削除できます)。

IListは、List、BindingList、ObservableCollectionなどのさまざまな具象クラスからリスト機能(カウント、追加、削除、インデクサーアクセス)を抽象化するインターフェイスです。


2
ここで受け入れられた回答によると、stackoverflow.com / questions / 1826658 /…です。IEnumerableのCountは、ICollectionのCountを呼び出そうとするのとほぼ同じです
Karsten

15
はいといいえ。Count()拡張メソッドは、IEnumerableがICollectionでもあるかどうかを確認し、そうである場合は、Countプロパティを呼び出します。IEnumerable ICollection でない場合、Count()はシーケンスの反復にフォールバックします。「IEnumerable のみを使用して要素をカウントするのは非常に非効率的」と言ったほうがいいかもしれません。もちろん、オブジェクトにIEnumerableが存在しても、より効率的なメソッドを使用できなくなるわけではなく、LINQ to Objects拡張メソッドが正確に実行しますそれ。
itowlson、2011年

16

IEnumerableは、アイテムのコレクション(foreachキーワードなど)による反復を可能にするインターフェースです。

配列は.NET組み込みです。同じタイプのアイテムを保持しますが、サイズは固定されています。x要素を持つ配列を作成すると、それを拡大または縮小することはできません。

IListはリストのインターフェイスを定義し、IEnumerableも実装します。

ListはIListインターフェイスを実装しています。リストの具体的なタイプです。

.NETリストと配列の違いは、リストに要素を追加できることです。これらの要素は、必要なすべてのアイテムを保持できるほど大きくなります。リストはこれを内部的に配列に格納し、配列がすべての要素を保持するのに十分な大きさでなくなると、新しい配列が作成され、項目がコピーされます。

IListと配列はどちらもIEnumerableを実装しています。これがインターフェイスのしくみです。クラスはコントラクトを実装し、同様の方法で動作し、結果として同様に処理できます(クラスがIEnumerableを実装していることを知っているので、方法や理由を知る必要はありません)。インターフェースなどを読むことをお勧めします。


1
すべての回答を読まない読者のためにこのコメントを追加します。配列とList <>はどちらもIList <>を実装します(配列はその多くを明示的に実装しています。おそらく、メンバーの多くがNotSupportedExceptionをスローするためです)。IListはIEnumerableを継承していると言った方が、実装していると言うよりも正しいです。
phoog

10

IEnumerableとIListはインターフェイスです。ArrayとListはクラスです。配列はIEnumerableを実装します。Listは、IEnumerableを拡張するIListを実装します。

編集:itowlsonがコメントで言及したように、ArrayはIListも実装します。


私もしませんでした!ただし、配列に対してIList.RemoveAtの呼び出しを開始するとどうなりますか?
マークシンプソン、

NotSupportedExceptionをスローします。(IList.RemoveAtおよび類似のIListメソッドは、通常の配列参照に表示されないように、配列に明示的に実装されていることに注意してください!)
itowlson

1
@itowlson System.Array(クラス自体)だけがIListを実装しますが、T []はIList <T>を実装しないことを指摘します。T []は代わりにIEnumerable <T>を実装します。私は、「アレイ」私見を求めたときにOPは必ずしものSystem.Arrayを求めていなかったと思う
USR-ローカルΕΨΗΕΛΩΝ

6

IEnumerableコレクションの生成は遅延です。例:

public IEnumerable<int> GetTwoInts()
{
  yield return 1;
  yield return 2;
}
public void Something()
{
  var twoInts = GetTwoInts();
}

メソッドSomethingでは、列挙が繰り返されないため、GetTwoInts()を呼び出しても、実際にはメソッドGetTwoIntsは実行されません。


もう少し詳しく説明してもらえますか?正しく理解できたかわかりません。後で実際にそのメソッドが実行されるコード行を表示できますか?ありがとう!
paaone 2013

@paaone twoIntsforeachor呼び出しを行いますtwoInts.ToList()
行1 2013

2

IEnumerableなど、多くのクラスで使用される汎用的なインタフェースでArrayListそしてStringコレクションを誰かの反復処理をさせるためです。基本的に、それがforeach声明を動かすものです。

IList通常、タイプの変数Listをエンドユーザーに公開する方法です。このインターフェイスは、基になるコレクションへのランダムアクセスを許可します。


2

他の回答を補完するために、そこにあることに注意して、性能差の間には、IList<T>List<T>foreach文を実行するとき。

これList<T>.GetEnumeratorは、によって返されるイテレータオブジェクトが値型であり、によって返されるイテレータオブジェクトIList<T>.GetEnumeratorが参照型であるため、メモリ割り当てが必要であるためです(c#のリストの値型の列挙子を参照)。

私の意見でIList<T>は、とにかく非常に良いインターフェースではありません。たとえば、呼び出しAddはスローすることができます(配列がIListを実装する理由を参照してください)。カプセル化が必要な場合は、IEnumerable<T>またはを使用することをお勧めしますIReadOnlyList<T>


1

他の回答に加えて、LINQを使用するときにEnumerableとList / Arrayの違いを理解すると、パフォーマンスに大きな影響を与える可能性があります。つまり、List / Arrayがクエリの結果である間、Enumerableはクエリビルダーとして認識されます。

EntityFrameworkを使用したLINQ to SQLのコンテキストでは、前者はSQLクエリを構築するだけで、データベースに対して実行したり、メモリにデータをロードしたりせず、後者は反対です。.ToList()ビジネスロジックを実行するためにメモリ内で必要になるまで呼び出しを延期するのはそのためです。

他のコンテキストでは、IEnumerableを返すLINQ式.ToList()は、が呼び出されるまで実行を延期します。以下の例を考えてみましょう:

void Main()
{
    var w1 = "AB".AsEnumerable();
    Console.WriteLine($"W1: 1");
    w1 = w1.Where(W1);
    Console.WriteLine($"W1: 2");
    w1 = w1.Where(W2);
    Console.WriteLine($"W1: 3");
    w1.ToList();    
    Console.WriteLine($"----------");

    var w2 = "CD".AsEnumerable();
    Console.WriteLine($"W2: 1");
    w2 = w2.Where(W1);
    Console.WriteLine($"W2: 2");
    w2 = w2.ToList();
    Console.WriteLine($"W2: 3");
    w2 = w2.Where(W2);
    Console.WriteLine($"W2: 4");
    w2.ToList();    
    Console.WriteLine($"----------");
}

bool W1(char arg)
{
    Console.WriteLine($"W1:{arg}");
    return true;
}

bool W2(char arg)
{
    Console.WriteLine($"W2:{arg}");
    return true;
}

OUTPUT:
W1: 1
W1: 2
W1: 3
W1:A
W2:A
W1:B
W2:B
----------
W2: 1
W2: 2
W1:C
W1:D
W2: 3
W2: 4
W2:C
W2:D
----------

最初の例では、2つ.Where()が「追加」さ.ToList()れ、アイテム「」で呼び出されたときに最後に一緒に実行されます A」が最初にパイプを通過し、次に項目「B」でため、出力に「AABB」が表示され、2番目の例では、これ.Where().ToList()、直後に呼び出すと毎回実行されるため、「CD」と「CD」が再度表示され、2回出力されます。したがって、Enumerableがリストまたは配列に変換されるたびに、1つのO(n)がかかります。に、コレクション内のすべてのアイテム反復が回、コレクションが大きい場合にパフォーマンスに影響します。

.ToList()LINQ呼び出しの間に呼び出すこの方法でコードを記述する傾向はありませんが、List/Arrayではなくを返す再利用可能なメソッドにコードを因数分解すると、より頻繁に発生しますIEnumerable

ただし、これは常にで操作する必要があるという意味ではありませんIEnumerabletowlsonが述べたようにで、などの操作.Count()はコレクションに対して反復を引き起こしますが、リストまたは配列はこの情報を事前に計算しているため、複数回List/Array呼び出す予定がある場合はへの変換がより効率的です.Count()。これは、カウント.Countする.Count()メソッドではなく、リストにプロパティがある理由でもあります。


0

これは古い投稿ですが、まだ返信を考えています。IEnumerableは動作ですが、Arrayはデータ構造です(固定サイズの要素の連続したコレクションで、インデックスによる要素へのアクセスを容易にします)。ArrayがIEnumerableを実装する場合、IEnumerable固有のプロパティも(コレクションの反復を容易にするために)表現することになっています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.