← Назад к вопросам

Приведи пример использования yield

2.0 Middle🔥 141 комментариев
#Коллекции и структуры данных#Основы C# и .NET

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Пример использования yield в C#

Ключевое слово yield в C# является частью механизма генераторов последовательностей и используется для создания ленивых вычислений (lazy evaluation) в методах-генераторах, возвращающих IEnumerable<T> или `IEnumerator<T>. Его основная цель — упростить написание перечислителей (enumerators), позволяя возвращать элементы последовательности по одному без необходимости создания временных коллекций.

Основные формы yield

yield используется в двух контекстах:

  • yield return — возвращает следующий элемент последовательности и временно "паузирует" выполнение метода до следующего обращения.
  • yield break — завершает генерацию последовательности, аналогично break в циклах.

Пример: Генерация последовательности чисел

Рассмотрим классический пример генерации последовательности чисел Фибоначчи с использованием yield.

using System;
using System.Collections.Generic;

public class FibonacciGenerator
{
    public static IEnumerable<int> GenerateFibonacci(int count)
    {
        int a = 0;
        int b = 1;

        for (int i = 0; i < count; i++)
        {
            yield return a; // Возвращаем текущее число и "паузируем" метод

            int temp = a;
            a = b;
            b = temp + b;
        }
    }
}

public class Program
{
    public static void Main()
    {
        // Получаем генератор для первых 10 чисел Фибоначчи
        IEnumerable<int> fibonacciSequence = FibonacciGenerator.GenerateFibonacci(10);

        // Итерируем по последовательности
        foreach (int number in fibonacciSequence)
        {
            Console.WriteLine(number);
        }
    }
}

Как это работает

  1. Метод GenerateFibonacci объявлен как возвращающий IEnumerable<int>, но он не возвращает готовую коллекцию. Вместо этого, при каждом вызове yield return, он возвращает одно значение и запоминает текущее состояние (значения переменных a, b и индекс i).
  2. При первом обращении в цикле foreach (или при вызове MoveNext() у энумератора), метод начинает выполнение и доходит до первого yield return.
  3. После возврата значения a (0), выполнение метода приостанавливается, а состояние сохраняется.
  4. При следующей итерации foreach, метод возобновляет выполнение с того места, где он был остановлен, продолжает цикл, вычисляет следующее число и снова вызывает yield return.
  5. Процесс повторяется до завершения цикла (или до вызова yield break).

Преимущества использования yield

  • Ленивое вычисление: Элементы генерируются только когда они действительно нужны, что экономит память и время, особенно для больших или бесконечных последовательностей.
  • Упрощение кода: Не требуется создавать временные списки или массивы для хранения всей последовательности перед возвратом.
  • Сохранение состояния: Автоматическое управление состоянием генератора без необходимости явно реализовывать IEnumerator<T>.

Пример с yield break

public static IEnumerable<int> GetNumbersUntilNegative(IEnumerable<int> source)
{
    foreach (int num in source)
    {
        if (num < 0)
        {
            yield break; // Завершаем генерацию при встрече отрицательного числа
        }
        yield return num;
    }
}

Применение в реальных задачах

yield часто используется в следующих сценариях:

  • Постепенная обработка больших данных (например, чтение файла по строкам).
  • Генерация бесконечных последовательностей (например, поток случайных чисел).
  • Реализация фильтрации и трансформации данных в стиле LINQ (многие стандартные LINQ методы используют yield внутри).
  • Создание асинхронных генераторов с yield в сочетании с IAsyncEnumerable<T> (в C# 8.0+).

Важные ограничения

  • Методы с yield не могут иметь возвращаемый тип void — они должны возвращать IEnumerable<T>, IEnumerator<T>, IAsyncEnumerable<T> или IAsyncEnumerator<T>.
  • yield нельзя использовать в лямбда-выражениях или анонимных методах.
  • Нельзя использовать yield внутри блоков try с конструкцией catch (можно только в блоке try с finally).

Таким образом, yield — это мощный инструмент для создания эффективных и читаемых генераторов последовательностей в C#, который широко применяется в реальных проектах для обработки данных.