Ответ
В C# и .NET отложенное (ленивое) выполнение — это стратегия, при которой вычисления откладываются до момента, когда результат действительно понадобится. Основные интерфейсы и типы:
1. IEnumerable<T> и IQueryable<T> (Отложенное выполнение запросов)
-
IEnumerable<T>: Базовый интерфейс для последовательностей. Запросы LINQ кIEnumerable(например,Where,Select) используют отложенное выполнение в памяти. Сама последовательность не обрабатывается, пока не начата итерация (например, вforeachили при вызовеToList()).var numbers = Enumerable.Range(1, 10); // Ещё ничего не вычислено var evenNumbers = numbers.Where(n => n % 2 == 0); // Построено выражение // Выполнение происходит здесь: foreach (var num in evenNumbers) { Console.WriteLine(num); } // Или при материализации: var list = evenNumbers.ToList(); -
IQueryable<T>: Наследует отIEnumerable<T>. Используется в LINQ провайдерах (как Entity Framework). Выражение запроса не выполняется немедленно, а преобразуется в другое представление (например, в SQL-запрос). Выполнение происходит при материализации или итерации.// EF Core пример var query = dbContext.Users .Where(u => u.Age > 18) .OrderBy(u => u.Name); // Строится выражение дерева // Запрос выполнится в БД только здесь: var adultUsers = query.ToList();
2. Lazy<T> (Отложенная инициализация)
- Класс, который инкапсулирует логику создания ресурсоёмкого объекта. Объект создаётся ровно один раз, при первом обращении к свойству
.Value. -
Зачем? Для оптимизации: избегаем затрат на создание объекта, если он может не понадобиться. Гарантирует потокобезопасное создание по умолчанию.
public class ExpensiveService { private readonly Lazy<HeavyResource> _resource = new Lazy<HeavyResource>(() => new HeavyResource()); public void Process() { // HeavyResource будет создан только при этом первом вызове _resource.Value.DoWork(); } }
3. IObservable<T> / IEnumerable<T> (Pull vs Push)
IEnumerableпредставляет pull-модель: потребитель "вытягивает" данные (черезforeach).IObservable<T>(из библиотеки Reactive Extensions - Rx.NET) представляет push-модель: источник данных "проталкивает" уведомления подписчикам. Последовательность вычисляется и отправляется по мере готовности, что также является формой отложенного выполнения для асинхронных потоков событий.