yield — это контекстное ключевое слово в C#, которое используется для создания итераторов и ленивого выполнения (lazy evaluation) последовательностей. Оно позволяет генерировать элементы коллекции по требованию, а не все сразу.
yield return <expression>; // Возвращает очередной элемент последовательности
yield break; // Завершает последовательность
Когда метод содержит оператор yield
, компилятор автоматически преобразует его в машину состояний, которая:
public static IEnumerable<int> GetNumbers(int max)
{
for (int i = 0; i < max; i++)
{
yield return i; // Возвращаем число и "запоминаем" позицию
}
}
// Использование
foreach (var num in GetNumbers(5))
{
Console.WriteLine(num); // Выводит 0, 1, 2, 3, 4
}
public static IEnumerable<string> GetUntilNull(IEnumerable<string> input)
{
foreach (var item in input)
{
if (item == null)
yield break; // Прерываем последовательность
yield return item;
}
}
Компилятор преобразует метод с yield в класс-итератор, реализующий IEnumerator<T>
. Для примера выше создается примерно такой код:
private sealed class <GetNumbers>d__0 : IEnumerable<int>, IEnumerator<int>
{
private int <>1__state;
private int <>2__current;
private int <>3__max;
private int <i>5__1;
// Реализация методов MoveNext, Current и т.д.
}
ref
или out
try-catch
, только try-finally
public static IEnumerable<int> Fibonacci()
{
int a = 0, b = 1;
while (true)
{
yield return a;
(a, b) = (b, a + b);
}
}
// Использование (с ограничением)
foreach (var num in Fibonacci().Take(10))
{
Console.WriteLine(num);
}
yield часто используется при реализации собственных LINQ-операторов:
public static IEnumerable<T> Where<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
foreach (var item in source)
{
if (predicate(item))
yield return item;
}
}
Оператор yield
— мощный инструмент для работы с последовательностями в C#, который позволяет реализовывать ленивые вычисления, экономить память и создавать эффективные итераторы. Он трансформирует метод в машину состояний, сохраняя позицию между вызовами и генерируя элементы по требованию.