linq
メソッド実行モード - 即時、遅延ストリーミング、遅延非ストリーミング
サーチ…
遅延実行と即時実行
一部のLINQメソッドはクエリオブジェクトを返します。このオブジェクトはクエリの結果を保持しません。代わりに、これらの結果を生成するために必要なすべての情報があります。
var list = new List<int>() {1, 2, 3, 4, 5};
var query = list.Select(x => {
Console.Write($"{x} ");
return x;
});
クエリにはConsole.Write
呼び出しが含まれていますが、コンソールに何も出力されていません。これは、クエリがまだ実行されていないため、 Select
渡された関数が評価されたことがないためです。これは、 遅延実行と呼ばれ、クエリの実行は後の時点まで遅延されます。
他のLINQメソッドは、クエリの即時実行を強制します。これらのメソッドはクエリを実行し、その値を生成します。
var newList = query.ToList();
この時点で、 Select
渡された関数は元のリストの各値に対して評価され、コンソールに次のものが出力されます:
1 2 3 4 5
一般に、単一の値( Max
やCount
)を返すLINQメソッドや、 ToList
やToDictionary
などの値を実際に保持するオブジェクトを返すLINQメソッドは、即座に実行されます。
IEnumerable<T>
またはIQueryable<T>
を返すメソッドはクエリオブジェクトを返し、後の時点まで実行を延期できます。
特定のLINQメソッドがクエリをすぐに実行するかどうかをMSDN - C#またはVB.NETで確認できます。
ストリーミングモード(レイジー評価)と非ストリーミングモード(熱心な評価)
遅延実行を使用するLINQメソッドの中には、一度に1つの値を評価する必要があるものがあります。次のコード:
var lst = new List<int>() {3, 5, 1, 2};
var streamingQuery = lst.Select(x => {
Console.WriteLine(x);
return x;
});
foreach (var i in streamingQuery) {
Console.WriteLine($"foreach iteration value: {i}");
}
出力されます:
3
foreach反復値:3
5
foreach反復値:5
1
foreach反復値:1
2
foreach反復値:2
Select
渡された関数はforeach
各反復で評価されるためです。これはストリーミングモードまたはレイジー評価と呼ばれます 。
他のLINQ方法-並べ替えとグループ化演算子は、 -彼らは任意の値を返すことができます前に、 すべての値が、評価することが必要です。
var nonStreamingQuery = lst.OrderBy(x => {
Console.WriteLine(x);
return x;
});
foreach (var i in nonStreamingQuery) {
Console.WriteLine($"foreach iteration value: {i}");
}
出力されます:
3
5
1
2
foreach反復値:1
foreach反復値:2
foreach反復値:3
foreach反復値:5
この場合、値をforeach
に昇順に生成する必要があるため、最小のものと次に小さいものを決定するために、すべての要素を最初に評価する必要があります。これは、 非ストリーミングモードまたは熱心な評価として知られています 。
特定のLINQメソッドがストリーミングモードでも非ストリーミングモードでも、MSDN - C#またはVB.NETにあります。
遅延実行の利点 - クエリの作成
遅延実行を使用すると、値を評価する前に、さまざまな操作を組み合わせて最終的なクエリを構築できます。
var list = new List<int>() {1,1,2,3,5,8};
var query = list.Select(x => x + 1);
この時点でクエリを実行すると、次のようになります。
foreach (var x in query) {
Console.Write($"{x} ");
}
私たちは次の出力を得るでしょう:
2 2 3 4 6 9
しかし、より多くの演算子を追加してクエリを変更することができます:
Console.WriteLine();
query = query.Where(x => x % 2 == 0);
query = query.Select(x => x * 10);
foreach (var x in query) {
Console.Write($"{x} ");
}
出力:
20 20 40 60
遅延実行のメリット - 現在のデータのクエリ
遅延実行では、問合せ対象のデータが変更された場合、問合せオブジェクトは定義時ではなく、実行時にデータを使用します。
var data = new List<int>() {2, 4, 6, 8};
var query = data.Select(x => x * x);
この時点で即時メソッドまたはforeach
を使用してクエリを実行すると、クエリは偶数のリストで動作します。
ただし、リストの値を変更した場合:
data.Clear();
data.AddRange(new [] {1, 3, 5, 7, 9});
たとえ新しいリストをdata
割り当てても、
data = new List<int>() {1, 3, 5, 7, 9};
クエリを実行すると、クエリは新しいdata
値で動作しdata
。
foreach (var x in query) {
Console.Write($"{x} ");
}
以下を出力します:
1 9 25 49 81