
Ленивый LINQ: разбираем yield и ленивые вычисления по кирпичикам
Deda_Sher 9 минут назад Ленивый LINQ: разбираем yield и ленивые вычисления по кирпичикам Средний 14 мин 247 C# * .NET * Программирование * Качество кода * Алгоритмы * Туториал Из песочницы ВведениеКаждый C#-разработчик...
<5 — 2026'da uzaya kaç SpaceX Starship fırlatması ulaşacak?
Значимый прорыв формирует отрасль ИИ: Deda_Sher 9 минут назад Ленивый LINQ: разбираем yield и ленивые вычисления по кирпичикам Средний 14 мин 247 C# * . NET * Программирование * Качество кода * Алгоритмы * Туториал Из песочницы ВведениеКаждый C#-разработчик хотя бы раз писал что-то вроде:var result = numbers. Take(5);И почти каждый на старте карьеры удивлялся, узнав, что эта строчка ничего не вычисляет.
Ни один элемент коллекции ещё не тронут, ни один предикат не вызван — вся цепочка спит. Вычисления начнутся только тогда, когда мы начнём перебирать result в foreach или вызовем . Для многих LINQ так и остаётся чёрным ящиком: работает — и слава богу.
Технические детали
Но за этим стоит вполне конкретный и воспроизводимый механизм — отложенные вычисления. Это подход, при котором код выполняется не в момент вызова метода, а только когда результат действительно понадобится. Это позволяет строить длинные цепочки преобразований без промежуточных коллекций, экономя память и процессорное время.
И никакой магии тут нет — в основе лежит обычная фича языка, доступная каждому: ключевое слово yield. В этой статье мы разберём, как устроены ленивые методы LINQ изнутри. Пройдём путь от наивной реализации без yield к тому, во что он на самом деле разворачивается компилятором, а дальше соберём из таких кирпичиков мини‑библиотеку, которая объяснит, почему одни методы не требуют памяти вообще, другие буферизуют данные частично, а третьи материализуют всю последовательность целиком, прежде чем отдать хоть один элемент.
К статье приложен репозиторий с реализацией куда большего числа методов — как без yield, так и с ним, — так что если какие‑то детали захочется рассмотреть подробнее, ссылка будет в конце. К концу статьи LINQ перестанет быть чёрным ящиком — вы будете точно знать, что происходит под капотом каждый раз, когда пишете . Погружаемся в историюИтак, представим, что мы пишем в старых версиях C#, в которых нет ни LINQ, ни ключевого слова yield.
Пусть нам требуется написать статический метод Where, которому будет передаваться предикат и он лениво будет возвращать отфильтрованную последовательность. Требования:1) Метод не должен ничего вычислять и не должен трогать исходную последовательность в момент вызова (отложенное выполнение)2) Метод должен возвращать объект, реализующий IEnumerable, чтобы результат можно было передать дальше по цепочке подобных методов или перебрать в foreach3) Сама фильтрация должна происходить оптимально по памяти: мы должны брать из исходного источника ровно столько элементов, сколько нужно, чтобы найти следующий подходящий, — и не больше. Никакого забегания вперёд и никакой промежуточной коллекции.
Событие, по словам экспертов, усилит конкуренцию в сфере ИИ.





