2012-03-25 6 views
3

私の質問は本当に簡単です。いつList、IEnumerable、ArrayListを使うべきですか?リスト<T>を使用する場合、IEnumerable <T>とArrayList

ここに私のシナリオがあります。私はLINQを使ってWebアプリケーションで作業しています。情報はIEnumerableとして返されます。

IEnumerable<Inventory> result = from Inventory i in db where.... 

IEnumerableの仕組みはよく分かりませんが、すべての操作には多くの時間がかかります。具体的には、result.Count()、result.ElementAt(i)、result.ToListなど、各操作にはかなりの時間がかかります。

IEnumerable変数を使用する代わりに、result.ToListを実行してこれをListとして処理する必要があるかどうかは疑問でした。

ありがとうございます!

+0

どのLINQプロバイダを使用していますか(つまり、どこからデータが届いていますか)リストのサイズはどれくらいですか? – Oded

+0

しかし、この場合、 'result.ToList'はIEnumerableで動作します。 –

+0

@ L.Bが言っているのは、あなたが見ている遅さが 'IEnumeralbe 'を使っているからではないということです。 – Oded

答えて

6

私はあなたが正しくやっていることを理解している場合、あなたはfrom Inventory i in db select iのようなクエリがあると、あなたが結果にいくつかの操作を行います。

var count = result.Count(); 
var fifth = result.ElementAt(5); 
var allItems = result.ToList(); 

は今、あなたは、異なる種類としてクエリを持っているときに何が起こるかを考えてみます。

  • IQueryable<T>

    var result = from Inventory i in db select i; 
    IQueryable<Inventory> result = from Inventory i in db select i; 
    

    上記の2行は同じです。実際にはデータベースには行きませんが、クエリの表現を作成するだけです。これがある場合、Count()SELECT COUNT(*) FROM InventoryのようなSQLクエリを実行します。ElementAt(5)はテーブルの5番目の項目のみを実行する別のクエリを実行し、はSELECT * FROM Inventoryのようなものを実行します。これを行う

  • IEnumerable<T>

    IEnumerable<Inventory> result = from Inventory i in db select i; 
    

    再びそれが唯一のクエリの表現を作成し、データベースを行っておりません。しかし、IQueryable<T>に固有のメソッドを使用できない表現であるため、LINQ操作によってコレクションが列挙され、SELECT * FROM InventoryのようなSQLクエリが実行されます。

    したがって、例:Count()は、SELECT * …クエリを実行して結果内の項目を数えます。 ElementAt(5)はクエリを再度に実行し、5番目のアイテムを除くすべてのアイテムを破棄します。 ToList()は、もう一度というクエリを実行します。

  • List<T>

    List<Inventory> result = (from Inventory i in db select i).ToList(); 
    

    これは実際にたらすぐにとSELECT * FROM Inventoryクエリを実行します。 resultで行うすべての操作はデータベースには触れず、メモリ内で行われます。

あなたはこれからどのような措置をとるべきですか?まず、は、というデータベースクエリのタイプとしてIEnumerable<T>を使用しないでください。それは恐ろしい性能を持っています。

結果にいくつかの異なる操作を行う場合は、IQueryable<T>を使用するのが最適な解決策です。

とにかく結果全体を取得する場合は、できるだけ早くToList()(またはToArray())を使用し、結果としてList<T>を使用してください。

2

ToList()などのメソッドを呼び出したときにのみクエリが実行されます。

これはDeffered Executionと呼ばれます。

resultの可能な限りIEnumerableを使用してください。実行LINQのパフォーマンスは、resultの用途に依存します。なぜなら、最終的にはIEnumerableとして扱われるからです。

ただし、LINQのパフォーマンスは、基礎となるデータによって異なります。

[DETAILS WITH編集しました]

+1

これは間違っています。データベースのLINQクエリを実行すると、効率的なSQLクエリー、IEnumerable (おそらく非常に効率的でないSQLクエリー)、リスト(リスト)(ToList()非常に効率的ではないかもしれません)。 – svick

+0

@Andriy私はコードをデバッグしました.LINQのパフォーマンスは問題ありません。問題は、IEnumerable変数や他の方法で要素にアクセスするときです。 – Gonzalo

+1

はい、ただし、クエリーが行われる基礎となるデータに依存します。質問は私が理解したように、結果変数についてです。 –

0

あなたはLINQクエリプロバイダに対するLINQの式を使用する場合、結果はIEnumerable<T>の延長であるIQueryable<T>、となります。

IQueryable<T>を反復処理するたびに、Linqクエリプロバイダは、基礎となるデータソースに対してクエリを実行します。したがって、結果を一度に繰り返し処理したい場合は、最初にリストに変換する方が効率的です(.ToList())。

結果をリストに変換するときは、拡張メソッドIEnumerable<T>の代わりにList<T>の実際のメンバーを使用する必要があります。例えば、list.ElementAt(i)list.Count()は、ともにO(n)の時間に実行され、list[i]list.Countは一定時間内に実行されます。

4

ArrayListを使用しないでください。 ArrayListは、以前の.NET 2.0との互換性のために保持されていました。 List<object>に相当し、通常の状況でジェネリックタイプを使用しない理由はありません。

LINQ to SQLまたは類似のフレームワークを使用してDBからデータを取得しているようです。この場合、selectステートメント自体はデータを取得せず、クエリを構成するだけです。 Count()やToList()のようなメソッドを呼び出すと、データが取得されます。これが遅い理由です。遅くなるわけではありませんが、それはただの怠惰なローディングです。

IEnumerableを使用する利点は、すべてのデータを一度に読み込む必要がないことです。特定のwhere句を使用してクエリを実行するか、またはTake(1)を呼び出して最初の要素を取得する場合、LINQプロバイダはスマートで、DBから必要な要素のみをフェッチする必要があります。しかし、Count()またはToList()を呼び出すと、データセット全体を取得する必要があります。そのような情報が必要な場合は、ToListまたはToArrayに電話し、残りの作業をメモリ内のリストで行い、再度DBにヒットする必要はないでしょう。

1

IEnumerableまたはIListを使用することの区別は、実際には(表面上で)非常に簡単です。

両方のインターフェイスで定義されている契約を見てください。 IEnumerableを使うと、シーケンスを列挙することができます。言い換えれば、データにアクセスする唯一の方法は、通常はforeachループで列挙子を使用することです。だから、カウント機能のナイーブな実装は次のようなものになるだろう:

public static int Count(this IEnumerable<T> source) { 
    int count = 0; 
    foreach(var item in myEnumerable) 
    { 
     count++; 
    } 
    return count; 
} 

これはあなたの列挙内の項目数を計算するのに必要な時間は、アイテムの数と直線的に増加することを意味します。また、これは内部的に格納されていないため、カウントするたびにこのループを実行する必要があります。

IListはすでにCountプロパティを公開しています。これは契約の一部です。 Count()を実装するには、単にCountプロパティへの呼び出しをラップします。これは、アイテムの数に関係なく同じ時間がかかります。

これについて考える簡単な方法は、(特にLinqを使用して)IEnumerableを必要な項目の仕様と考えることです。データにアクセスしない限り、構築する時間はほとんどありません。列挙を開始すると(基本的にIEnumerable以外のものを返すもの)、コードが実行され、時間がかかることがあります。

あなたのコンテキストに関して、私が通常やりたいことは、コントローラ内でLinqの実行を保つことです。だから、私はクエリをビルドしてから、ToListまたはToArrayをビューに送ります。理由は非常に単純です。ビューのデータに単にアクセスする以外に何かをしなければならないとすれば、私は自分の見解ではあまりにも多くのことをしていることを意味します。私は今、私の意見を可能な限りきれいに保ちながら、その論理を私のコントローラーのアクションに移すことを余儀なくされています。

0

一般的なリスト/可能な限りIEnumerableを使用します。

ArrayListを避けてください。これにより、値型のボクシングや参照型のキャストが発生する可能性があります。 IEnumerableは同じです。オブジェクトを扱わない限り、避けてください。

IEnumerable<T>は、非常に優れた共分散、反分散特性を示します。しかし、それは祝福ほど呪いであるdelayed executionと表示されます。

List<T>は、インターフェイスを公開している間は内部での使用に適しています(IEnumerable<T>)。 List<T>は反差異をサポートしていません。

0

使用する答えは「依存しますが、主にリストを使用します」です。

あなたの質問の完全な内容(.Count()や他のメソッドを実行する長い遅延)に基づいて、まずクエリの結果に対してtoList()を実行し、その後のアクセスにそれを使用する必要があります。

ここに理由があります。 IEnumerableはかなりのクエリです。照会されるデータは照会の実行間で変更される可能性があるため、そのIEnumerableに対する単一のメソッド呼び出しによって、別のデータベース参照が行われます。

したがって、.Count()を呼び出すたびに、データベースにアクセスしてクエリに一致するすべてのオブジェクトの数を取得する必要があります。 elementAt(x)を実行するたびにxが変更されなくても、データが変更されていないとIEnumerableが想定できないため、誰かがデータベースを通過して何かを取得する必要があります。

一方、Listを使用してクエリのスナップショットを取得した場合、Countを取得するかランダム要素にアクセスするのはかなり高速です。

だから、これは使用する - それは依存します。IEnumerableにアクセスするたびに、データベース(または何らかのデータソース)に何があるかを知る必要があります。次に、IEnumerableを使用する必要があります。最初のクエリを実行したときや、一貫性のある(および/または静的な)データソースに対して操作を実行する必要があるときだけ気にする場合は、Listを使用します。最初のアクセスではまだ時間がかかりますが、それ以外のものは速くなります。

関連する問題