Что делает "yield break;" в С#?

Я видел этот синтаксис в MSDN: yield break, но я не знаю, что он делает. Кто-нибудь знает?

Ответ 1

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

Например, если вы определяете функцию как итератор, тело функции может выглядеть так:

for (int i = 0; i < 5; i++)
{
    yield return i;
}

Console.Out.WriteLine("You will see me");

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

Или, например, с yield break:

int i = 0;
while (true)
{
    if (i < 5)
    {
        yield return i;
    }
    else
    {
        // note that i++ will not be executed after this
        yield break;
    }
    i++;
}

Console.Out.WriteLine("Won't see me");

В этом случае последнее утверждение никогда не выполняется, потому что мы рано оставили функцию.

Ответ 2

Заканчивает блок итератора (например, говорит, что в IEnumerable больше нет элементов).

Ответ 3

Сообщает итератору, что он достиг цели.

В качестве примера:

public interface INode
{
    IEnumerable<Node> GetChildren();
}

public class NodeWithTenChildren : INode
{
    private Node[] m_children = new Node[10];

    public IEnumerable<Node> GetChildren()
    {
        for( int n = 0; n < 10; ++n )
        {
            yield return m_children[ n ];
        }
    }
}

public class NodeWithNoChildren : INode
{
    public IEnumerable<Node> GetChildren()
    {
        yield break;
    }
}

Ответ 4

yield в основном заставляет метод IEnumerable<T> вести себя аналогично совместному (в отличие от упреждающего) планового потока.

yield return похож на поток, вызывающий функцию "расписание" или "сон", чтобы отказаться от управления процессором. Точно так же, как поток, метод IEnumerable<T> восстанавливает элементы управления в точке сразу же после того, как все локальные переменные имеют те же значения, что и до того, как управление было отброшено.

yield break похож на поток, достигающий конца его функции и завершающий.

Люди говорят о "машине состояния", но машина состояния - это "поток". Поток имеет некоторое состояние (I.e. значения локальных переменных), и каждый раз, когда он запланирован, для достижения нового состояния требуется некоторое действие (действия). Ключевым моментом в отношении yield является то, что в отличие от потоков операционной системы, к которым мы привыкли, используемый в нем код замораживается до тех пор, пока итерация не будет выполнена вручную или не будет завершена.

Ответ 6

Здесь http://www.alteridem.net/2007/08/22/the-yield-statement-in-c/ - очень хороший пример:

public static IEnumerable<int> Range( int min, int max )
{
   while ( true )
   {
      if ( min >= max )
      {
         yield break;
      }
      yield return min++;
   }
}

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

Ответ 7

Если то, что вы подразумеваете под словом "то, что действительно дает перерыв", - "как это работает" - см. блог Raymond Chen для более подробной информации http://blogs.msdn.com/oldnewthing/archive/2008/08/12/8849519.aspx

Итераторы С# генерируют очень сложный код.

Ответ 8

Оператор yield break заставляет перечисление останавливаться. Фактически, yield break завершает перечисление без возврата каких-либо дополнительных элементов.

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

IEnumerable<uint> FindPrimes(uint startAt, uint maxCount)
{
    for (var i = 0UL; i < maxCount; i++)
    {
        startAt = NextPrime(startAt);
        yield return startAt;
    }

    Debug.WriteLine("All the primes were found.");
}

В приведенном выше примере метод итератора, естественно, прекратит выполнение, как только будут найдены простые числа maxCount.

Оператор yield break - это еще один способ перечислить итератор. Это способ вырваться из перечисления на ранней стадии. Вот тот же метод, что и выше. На этот раз метод имеет ограничение на количество времени, которое может выполнить метод.

IEnumerable<uint> FindPrimes(uint startAt, uint maxCount, int maxMinutes)
{
    var sw = System.Diagnostics.Stopwatch.StartNew();
    for (var i = 0UL; i < maxCount; i++)
    {
        startAt = NextPrime(startAt);
        yield return startAt;

        if (sw.Elapsed.TotalMinutes > maxMinutes)
            yield break;
    }

    Debug.WriteLine("All the primes were found.");
}

Обратите внимание на вызов yield break. По сути, он рано выходит из списка.

Заметьте, что yield break работает иначе, чем просто break. В приведенном выше примере yield break завершает метод без вызова Debug.WriteLine(..).

Ответ 9

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

Чтобы объяснить смысл с помощью примера:

    public IEnumerable<int> SampleNumbers()
    {
        int counter = 0;
        yield return counter;

        counter = counter + 2;

        yield return counter;

        counter = counter + 3;

        yield return counter ;
    }

Значения, возвращаемые при повторении: 0, 2, 5.

Важно отметить, что переменная счетчика в этом примере является локальной переменной. После второй итерации, которая возвращает значение 2, третья итерация начинается с того места, где она была ранее, при сохранении предыдущего значения локальной переменной с именем counter, которая равна 2.