C# Academy · Урок

yield break и досрочное завершение

Условно прекращайте итерацию.

Урок 2 из 413 шагов

«yield break и досрочное завершение» — бесплатный урок C# Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 4 уроков всего.

Досрочная остановка итератора

Иногда нужно, чтобы итератор перестал выдавать значения до естественного завершения. Оператор yield break немедленно завершает последовательность, подобно оператору return для итераторов.

Основы досрочного завершения итератора

yield break завершает итератор. Новые значения больше не выдаются, и цикл foreach, потребляющий последовательность, завершается.

using System;
using System.Collections.Generic;

public class Program
{
    static IEnumerable<int> UpToFive()
    {
        for (int i = 1; i <= 100; i++)
        {
            if (i > 5) yield break;
            yield return i;
        }
    }

    public static void Main()
    {
        foreach (var n in UpToFive())
            Console.WriteLine(n);
    }
}

Выдача значений, пока выполняется условие

Распространённый шаблон — выдавать элементы только пока условие истинно, а затем остановиться. Оператор yield break делает это понятным.

using System;
using System.Collections.Generic;

public class Program
{
    static IEnumerable<int> WhileSmall(IEnumerable<int> nums)
    {
        foreach (var n in nums)
        {
            if (n >= 10) yield break;
            yield return n;
        }
    }

    public static void Main()
    {
        foreach (var n in WhileSmall(new[] { 2, 4, 8, 12, 3 }))
            Console.WriteLine(n);
    }
}

Защитные условия с досрочным завершением итератора

Вы можете использовать yield break в начале итератора как защитную проверку. Если входная последовательность пуста или недействительна, не возвращайте ни одного элемента.

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    static IEnumerable<string> Lines(string text)
    {
        if (string.IsNullOrEmpty(text)) yield break;
        foreach (var line in text.Split('\n'))
            yield return line;
    }

    public static void Main()
    {
        foreach (var l in Lines("a\nb\nc"))
            Console.WriteLine(l);
        Console.WriteLine("empty count: " + Lines("").Count());
    }
}

Ограничение количества результатов

Используйте счётчик вместе с yield break, чтобы ограничить количество элементов, выдаваемых итератором, даже при работе с длинным источником.

using System;
using System.Collections.Generic;

public class Program
{
    static IEnumerable<int> Take(IEnumerable<int> source, int max)
    {
        int count = 0;
        foreach (var item in source)
        {
            if (count++ >= max) yield break;
            yield return item;
        }
    }

    public static void Main()
    {
        foreach (var n in Take(new[] { 1, 2, 3, 4, 5 }, 3))
            Console.WriteLine(n);
    }
}

Остановка вызывающего кода и досрочное завершение итератора

Последовательность может завершиться двумя способами. Вызывающий код может перестать запрашивать значения с помощью break, либо итератор может прекратить их выдачу с помощью yield break. Оба способа завершают цикл, но по разным причинам.

using System;
using System.Collections.Generic;

public class Program
{
    static IEnumerable<int> Counting()
    {
        int i = 1;
        while (true) yield return i++;
    }

    public static void Main()
    {
        // Caller decides to stop with break
        foreach (var n in Counting())
        {
            if (n > 3) break;
            Console.WriteLine(n);
        }
    }
}

Досрочное завершение затрагивает только текущий итератор

yield break завершает метод-итератор, в котором находится, но не внешний цикл вызывающего кода. Управление возвращается тому, кто перебирал последовательность.

using System;
using System.Collections.Generic;

public class Program
{
    static IEnumerable<int> Bounded(IEnumerable<int> nums, int limit)
    {
        foreach (var n in nums)
        {
            if (n > limit) yield break; // ends Bounded only
            yield return n;
        }
    }

    public static void Main()
    {
        var result = Bounded(new[] { 1, 2, 9, 3 }, 5);
        Console.WriteLine("iterator created, still running");
        foreach (var n in result) Console.WriteLine(n);
    }
}

После досрочного завершения нет выдачи значений

После выполнения yield break итератор завершён. Любой код, расположенный после него на том же пути выполнения, больше не может выдавать значения.

using System;
using System.Collections.Generic;

public class Program
{
    static IEnumerable<int> Demo(bool stopEarly)
    {
        yield return 1;
        if (stopEarly) yield break;
        yield return 2;
        yield return 3;
    }

    public static void Main()
    {
        Console.WriteLine("stopEarly = true:");
        foreach (var n in Demo(true)) Console.WriteLine(n);
        Console.WriteLine("stopEarly = false:");
        foreach (var n in Demo(false)) Console.WriteLine(n);
    }
}

Сочетание фильтрации и досрочной остановки

В одном итераторе можно одновременно фильтровать и завершать выполнение: пропускать одни значения, выдавать другие и полностью прекращать работу при появлении специального значения.

using System;
using System.Collections.Generic;

public class Program
{
    static IEnumerable<int> UntilZero(IEnumerable<int> nums)
    {
        foreach (var n in nums)
        {
            if (n == 0) yield break;     // stop at sentinel
            if (n < 0) continue;         // skip negatives
            yield return n;
        }
    }

    public static void Main()
    {
        foreach (var n in UntilZero(new[] { 3, -1, 5, 0, 9 }))
            Console.WriteLine(n);
    }
}

Оператор yield break и блоки finally

Если в Вашем итераторе есть конструкция try/finally, блок finally всё равно выполняется, когда yield break завершает последовательность. Это гарантирует очистку, например закрытие ресурсов.

using System;
using System.Collections.Generic;

public class Program
{
    static IEnumerable<int> WithCleanup()
    {
        try
        {
            yield return 1;
            yield break;
        }
        finally
        {
            Console.WriteLine("cleanup ran");
        }
    }

    public static void Main()
    {
        foreach (var n in WithCleanup())
            Console.WriteLine(n);
    }
}

Попробуйте сами

Объедините фильтрацию и досрочное завершение: выдавайте положительные числа, но полностью остановитесь, как только их текущая сумма превысит бюджет.

using System;
using System.Collections.Generic;

public class Program
{
    static IEnumerable<int> WithinBudget(IEnumerable<int> nums, int budget)
    {
        int spent = 0;
        foreach (var n in nums)
        {
            if (n <= 0) continue;
            if (spent + n > budget) yield break;
            spent += n;
            yield return n;
        }
    }

    public static void Main()
    {
        foreach (var n in WithinBudget(new[] { 3, -2, 4, 5, 1 }, 10))
            Console.WriteLine(n);
    }
}

Быстрая проверка

Вспомните назначение yield break.

Итоги

yield break досрочно завершает итератор.

  • Он работает как return без значения для итераторов.
  • Используйте его для логики «брать, пока выполняется условие», защитных проверок и ограничения количества элементов.
  • Он завершает только итератор, а не цикл вызывающего кода.
  • Блоки finally всё равно выполняются, обеспечивая очистку.
Можно начать бесплатно

Изучай C# с ИИ-репетитором — бесплатно

Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.

Курсы
93
Уроки
346

Часто задаваемые вопросы

Урок «yield break и досрочное завершение» бесплатный?

Да — полный текст урока «yield break и досрочное завершение» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 4 уроков всего.

Чему я научусь в уроке «yield break и досрочное завершение»?

Условно прекращайте итерацию. Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C# Academy?

Предыдущий опыт не требуется. C# Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.

Сколько времени занимает урок «yield break и досрочное завершение»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C# Academy?

Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Методы-итераторы с yield return
  2. yield break и досрочное завершение
  3. Семантика ленивого вычисления
  4. Пользовательские перечисляемые типы
← Назад к C# Academy