2016-08-17 17 views
5

あなたはLINQの拡張メソッドを使用するか、クエリ演算子を使用するか、可算集合を定義するためにLINQを使用すると、アプリケーション が実際にLINQ 延長した時点でコレクションを構築しません。メソッドが実行されます。コレクションは、 を反復処理するときにのみ列挙されます。つまり、元の コレクションのデータは、LINQクエリを実行してクエリが識別するデータを取得する間に変更される可能性があります。最新のデータである を常に取得します。私は次のコードで書かれているのLINQと遅延評価

ジョン・シャープによって書かれたステップバイ

のMicrosoft Visual C#の2013ステップ:

List<int> numbers = new List<int>() { 1, 2, 3, 4, 5 }; 
IEnumerable<int> res = numbers.FindAll(a => a > 0).Select(b => b).ToList(); 
numbers.Add(99); 
foreach (int item in res) 
    Console.Write(item + ", "); 

上記のコードの結果は怒鳴るようになります。

1,2,3,4,5,

なぜこのようになりますか?私はFuncActionおよびPredicateについて知っていますが、私はここで何が起こっているのか理解できません。上記の定義に基づいて、コードは合理的ではありません。

+1

最後にToList()を削除してみてください –

+0

@MatiasCicero私は試しましたが効果はありませんでした。 – Media

+2

'ToList()'は* new * list( 'res')を作成して全てのアイテムをコピーしますが、* old *(' numbers')に追加します –

答えて

6

新しいコレクションを作成している最後のToList()は別として、別の問題があります。

問題は、LINQをまったく使用していないことです。

FindAllは、LINQ拡張メソッドではありません。

あなたはWhereを使用する必要があります。

List<int> numbers = new List<int>() { 1, 2, 3, 4, 5 }; 
IEnumerable<int> res = numbers.Where(a => a > 0); 

numbers.Add(99); 

foreach (int item in res) 
    Console.Write(item + ", "); 
+3

これは実際の原因であり、唯一の完全な答えです。私は 'FindAll'を完全に読み飛ばしました。 –

1

foreachループまでToList()の操作を延期(またはすべて削除)すると、結果が表示されます。 ToListは列挙と同じLinq式を実行します。

List<int> numbers = new List<int>() { 1, 2, 3, 4, 5 }; 
IEnumerable<int> res = numbers.FindAll(a => a > 0).Select(b => b); 

numbers.Add(99); 

foreach (int item in res) 
    Console.Write(item + ", "); 

// another option, but not necessary in most cases... 
foreach (int item in res.ToList()) 
    Console.Write(item + ", "); 
+1

まだ1,2,3,4,5、 ' –

+0

@GlennFerrieがコメントに記載されていますが、ToList()を削除すると適切な答えが表示されません99.これをVisual Studioで試してみました2013年は動作しませんでした。 – Media

2

まず、1,2,3,4,5を含むint型リストを設定します。 次に、linqを使用して列挙型コレクションを作成および定義しました。ここでは はlinqの働きについて説明しています:上記のリストのすべての項目が0より大きい場合は、まずゼロより大きいすべての数値を見つけ、それらのすべてを選択してリストに入れます。番号リストに99を追加すると、定義された列挙コレクションには影響しません。なぜなら、新しいコレクションを作成し、そこにアイテムを渡し、番号リストへの参照がないからです。 linq式の最後に.ToList()を削除すると、結果は次のようになります。 1,2,3,4,5,99。

グッドラック

+0

実際に私はあなたがdeffered評価を気にしていないと思います。 – Media

2

ToListList<T>新しいインスタンスを作成し、そこにすべての項目をコピーします。

http://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,e276d6892241255b

public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source) { 
    if (source == null) throw Error.ArgumentNull("source"); 
    return new List<TSource>(source); 
} 

ですから、res99にあなたがしたい場合はに追加するか、numbers

に追加しないでください。
... 
var res = numbers 
    .Where(a => a > 0) // Filter out; Select is redundant 
    .ToList(); 

res.Add(99); 

Console.Write(string.Join(", ", res)); 
2

ToList()は実際には唯一の問題ではありません。 FindAllは新しいListを返します。あなたは

IEnumerable<int> res = numbers.FindAll(a => a > 0) 

を呼び出すときですから、数字に新しい項目を追加するときに、それはもはや適切である

IEnumerable<int> newList = new List<int>(); 
foreach (int old in numbers) { 
    if (old > 0) newList.Add(old); 
} 

をやってと同じではないこと。元のリストではなく、FindAllによって返されたリストに対して検索しています。