サーチ…


遅延実行と即時実行

一部の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


一般に、単一の値( MaxCount )を返すLINQメソッドや、 ToListToDictionaryなどの値を実際に保持するオブジェクトを返す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



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow