| layout | default | ||||
|---|---|---|---|---|---|
| title | 🕰️ Что такое отложенные (deferred) и немедленные (immediate) запросы в LINQ? | ||||
| description | |||||
| author | Dvurechensky | ||||
| date | 2025-08-28 | ||||
| published | true | ||||
| tags |
|
- Deferred execution (отложенное выполнение): запрос не выполняется сразу, а откладывается до момента, когда к результату обращаются (
foreach,ToList(),Count(),First()). - Immediate execution (немедленное выполнение): запрос выполняется сразу, данные материализуются в память.
- Выполнение запроса откладывается до момента итерации.
- Все стандартные LINQ методы для
IEnumerable<T>(например,Where,Select,Take) отложенные. - Пример:
List<int> numbers = new() {1,2,3,4,5};
var query = numbers.Where(n => n > 2); // ещё не выполняется
numbers.Add(6); // это повлияет на результат
foreach(var n in query)
{
Console.WriteLine(n); // теперь выполняется, выводит 3,4,5,6
}Особенности:
- Отложенное выполнение реагирует на изменения источника данных.
- Экономит память, особенно при больших коллекциях.
- Позволяет строить цепочки фильтров и трансформаций, которые не создают новые коллекции.
Примеры отложенных методов:
WhereSelectTake,SkipOrderBy,ThenBySelectMany
- Выполнение запроса происходит сразу, результат сохраняется в коллекции.
- Пример:
var numbersList = numbers.Where(n => n > 2).ToList(); // выполняется сразу
numbers.Add(7);
Console.WriteLine(numbersList.Count); // не учитывает 7Методы немедленного выполнения:
ToList(),ToArray()Count(),LongCount()Sum(),Average(),Min(),Max()First(),FirstOrDefault(),Single(),SingleOrDefault()Any(),All(),Contains()
| Характеристика | Deferred Execution | Immediate Execution |
|---|---|---|
| Когда выполняется | При итерации | Сразу при вызове метода |
| Память | Минимально | Все результаты материализуются |
| Влияние изменений источника | Да | Нет, результат фиксирован |
| Методы LINQ | Where, Select, Take, Skip, OrderBy | ToList, ToArray, Count, First, Sum, etc. |
| Производительность | Эффективно при больших данных | Может быть дороже для больших данных |
-
Изменение источника данных
-
Отложенный запрос учитывает изменения:
var query = list.Where(x => x > 0); list.Add(10); foreach(var n in query) { ... } // включает 10
-
Немедленный запрос игнорирует изменения после материализации.
-
-
Повторная итерация
- Deferred: каждый
foreachвыполняет запрос заново. - Immediate: данные уже в памяти, повторная итерация не вызывает повторного выполнения.
- Deferred: каждый
-
LINQ to SQL / IQueryable
- Deferred — SQL запрос формируется, но не выполняется до
ToList()илиforeach. - Immediate —
ToList(),Count()вызывают фактический запрос к БД.
- Deferred — SQL запрос формируется, но не выполняется до
-
Побочные эффекты
- Если источник данных изменяется или имеет методы с побочными эффектами, Deferred может вызывать их несколько раз.
- Immediate фиксирует результат один раз.
-
Накладные расходы
- Deferred экономит память, но при многократной итерации может выполнять один и тот же запрос несколько раз.
- Immediate: больше памяти, меньше повторных вычислений.
var numbers = new List<int> {1,2,3};
var query = numbers.Where(n => n > 1); // Deferred
numbers.Add(4);
foreach(var n in query) Console.WriteLine(n); // 2,3,4var numbers = new List<int> {1,2,3};
var result = numbers.Where(n => n > 1).ToList(); // Immediate
numbers.Add(4);
foreach(var n in result) Console.WriteLine(n); // 2,3✨Dvurechensky✨