2008-10-23 4 views
380

Я видел этот синтаксис в MSDN: yield break, но я не знаю, что он делает. Кто-нибудь знает?Что означает «выход из строя»; делать в C#?

+16

Однако документация MSDN упоминает его, но не объясняет. Это плохой способ дразнить голодного разработчика знаний. – Phil 2012-06-28 17:11:04

+2

Возврат доходности исключает необходимость в резервном списке, то есть вам не нужно кодировать что-то вроде `MyList.Add (...)` just do `yield return ...`. Если вам нужно выйти из цикла преждевременно и вернуть список виртуальных резервных копий, вы используете `yield break`,` – 2013-08-26 21:16:47

+0

Солидный совет от «The Muffin Man» – 2015-08-28 17:52:41

ответ

418

Он указывает, что итератор пришел к концу. Вы можете думать о 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"); 

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

45

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

+1

с [+1] - хотя в академическом плане итераторов нет в .NET. , только одно перечисление (одно направление, вперед.) – 2016-05-13 19:57:11

+0

@Shaun Wilson, но с ключевым словом `yield` вы можете итерировать коллекцию в обоих направлениях, причем вы можете принимать каждый следующий элемент коллекции не в строке – monstr 2017-03-08 21:07:51

+0

@monstr, вы можете итерировать коллекцию в любом и вам не нужно «уступать», чтобы это сделать. Я не говорю, что вы ошибаетесь, я понимаю, что вы предлагаете; но, как академически, в .NET нет итераторов, только перечисляющие (одно направление, вперед) - в отличие от stdC++ нет «универсальной структуры итератора», определенной в CTS/CLR.LINQ помогает закрыть пробел с помощью методов расширения, которые используют `yield return` **, а также методы обратного вызова **, но они являются первоклассными методами расширения, а не первоклассными итераторами. результирующий `IEnumerable` не может сам перебираться в любом направлении, кроме переадресации вызывающего. – 2017-03-10 20:51:47

4

Если то, что вы имеете в виду «что делает выход перерыв действительно», «как это работает» - Смотрите блог Реймонда Чена Подробности http://blogs.msdn.com/oldnewthing/archive/2008/08/12/8849519.aspx

C# итераторы сгенерировать очень сложный код.

27

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

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

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; 
    } 
} 
18

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 оператор попал в методе, выполнение этого метода останавливается без возвращения. Есть некоторые временные ситуации, когда вы не хотите давать никакого результата, тогда вы можете использовать прерывание выхода.

0

Ключевое слово 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, третья итерация начинается, где она была раньше, сохраняя при этом предыдущее значение локальных переменного с именем счетчиком который был 2.

4

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(..).

Смежные вопросы