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
Как правило, методы 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