В LINQ существует два принципиально разных подхода к выполнению запросов:
Отложенное исполнение (Deferred Execution)
Немедленное исполнение (Immediate Execution)
Характеристики:
IEnumerable<T>
или IQueryable<T>
Примеры методов:
Where()
Select()
OrderBy()
GroupBy()
Пример:
var numbers = new List<int> { 1, 2, 3, 4, 5 };
var query = numbers.Where(n => n > 2); // Запрос НЕ выполняется здесь
numbers.Add(6); // Модификация исходных данных
foreach (var num in query) // Запрос выполняется ПРИ ПЕРЕЧИСЛЕНИИ
{
Console.WriteLine(num); // Выведет 3, 4, 5, 6
}
Характеристики:
Примеры методов:
ToList()
ToArray()
Count()
First()
Average()
Пример:
var numbers = new List<int> { 1, 2, 3, 4, 5 };
var result = numbers.Where(n => n > 2).ToList(); // Запрос выполняется СРАЗУ
numbers.Add(6); // Модификация исходных данных
foreach (var num in result)
{
Console.WriteLine(num); // Выведет только 3, 4, 5
}
Отложенное исполнение:
// Запрос выполняется дважды (при каждом foreach)
var query = data.Where(x => x.IsValid).Select(x => x.Value);
foreach (var item in query) { ... }
foreach (var item in query) { ... }
Немедленное исполнение:
// Запрос выполняется один раз
var list = data.Where(x => x.IsValid).Select(x => x.Value).ToList();
foreach (var item in list) { ... }
foreach (var item in list) { ... }
Для LINQ to SQL/Entity Framework отложенные запросы особенно важны:
var dbQuery = context.Products
.Where(p => p.Price > 100) // Строится выражение
.OrderBy(p => p.Name); // SQL не выполняется
// Запрос выполняется ТОЛЬКО здесь:
var results = dbQuery.ToList(); // Генерация и выполнение SQL
Отложенное исполнение полезно:
Немедленное исполнение нужно:
// Отложенное исполнение позволяет комбинировать запросы
IEnumerable<Product> GetFilteredProducts(List<Product> products,
Func<Product, bool> filter)
{
return products.Where(filter);
}
// Запрос будет выполнен только при вызове ToList()
var filtered = GetFilteredProducts(products, p => p.Price > 100)
.OrderBy(p => p.Name)
.ToList(); // Материализация происходит здесь
Отложенное исполнение в LINQ позволяет оптимизировать выполнение запросов, откладывая их фактическое выполнение до момента реальной необходимости, в то время как немедленное исполнение сразу материализует результаты. Понимание этой разницы критически важно для написания эффективных LINQ-запросов, особенно при работе с базами данных или большими объемами данных.