Поиск…


Отсроченное исполнение и немедленное исполнение

Некоторые методы 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


Как правило, методы LINQ, которые возвращают одно значение (например, Max или Count ) или возвращают объект, который фактически содержит значения (например, ToList или ToDictionary ), выполняются немедленно.

Методы, возвращающие IEnumerable<T> или IQueryable<T> , возвращают объект запроса и позволяют отложить выполнение до более поздней точки.

Определяет ли конкретный метод LINQ запрос для немедленного выполнения запроса, может быть найден на MSDN - C # или VB.NET .

Режим потоковой передачи (ленивая оценка) против режима без потоковой передачи (нетерпеливая оценка)

Из методов LINQ, которые используют отложенное выполнение, некоторые требуют одновременного вычисления одного значения. Следующий код:

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 :

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