День 1499. #ЗаметкиНаПолях
Как Использовать yield break в C#?
Когда мы помещаем оператор yield внутрь метода, компилятор обрабатывает этот метод как метод (блок) итератора. Метод итератора может возвращать IEnumerable, IEnumerator, IEnumerable<T> или IEnumerator<T>. Он использует оператор yield return для возврата элементов один за другим. Компилятор обрабатывает метод итератора не так, как обычный метод. Про yield return я уже писал ранее, сегодня рассмотрим yield break.
Как только мы определим метод итератора с помощью yield return, нам понадобится способ остановить итерацию в какой-то момент. Например, когда выполняется какое-то условие, или после выполнения заданного количества итераций и т. д. Для этой цели мы можем использовать оператор yield break. Он завершит итерацию и выйдет из блока итератора. Рассмотрим метод, который будет генерировать случайные года между 1901 и 2023. Он будет выполняться бесконечно, поэтому прервём его, если будет найден високосный год:
public static class Utils
{
private static Random random = new();
public static IEnumerable<int> RandomYears()
{
int year;
while (true)
{
year = random.Next(1901, 2023);
yield return year;
if (year % 4 == 0)
{
Console.WriteLine($"Leap Year:{year}");
yield break;
}
}
Console.WriteLine($"Finished");
}
}
Теперь посмотрим на результаты:
foreach (int year in Utils.RandomYears())
Console.WriteLine(year);
Вывод:
1937
1986
1942
1920
Leap Year:1920
Может возникнуть вопрос: можем ли мы просто использовать break для завершения итерации вместо yield break? Да, но они ведут себя по-разному:
- yield break внутри блока итератора полностью завершает блок итератора и выходит из метода. Даже если после цикла есть какие-то операторы, компилятор их не выполнит. Как это видно в результатах выше, нет строки “Finished”. В этом случае компилятор даже выдаст предупреждение о том, что он обнаружил недостижимый код.
- break внутри цикла, он завершает цикл и выполняет следующий оператор после цикла. Т.е., если есть другие операторы после цикла, компилятор все равно выполнит их перед выходом из метода.
Если в коде выше заменить yield break на break и выполнить код, мы увидим выполнение оператора после цикла:
1969
1995
1920
Leap Year:1920
Finished
Мы можем думать об операторе yield break внутри метода итератора как о чём-то похожем на оператор return внутри обычного метода, который ничего не возвращает. Но можем ли мы просто использовать return для выхода из итератора вместо использования yield break? Нет. Мы увидим ошибку компиляции: CS1622 - Cannot return a value from an iterator. Use the yield return statement to return a value, or yield break to end the iteration. (Невозможно вернуть значение из итератора. Используйте оператор yield return, чтобы вернуть значение, или yield break, чтобы завершить итерацию.)
Итого
Методы итератора отличаются от обычных методов и не поддерживают обычные операторы возврата. Он может использовать только операторы yield return и yield break. Это очень важное различие между методами итератора и обычными методами. Метод итератора может иметь операторы «yield return» для возврата значений одно за другим и операторы yield break для выхода из итератора. Но мы не можем использовать обычный оператор return в методе итератора.
Источник: https://code-maze.com/csharp-yield-break/