




Завершает блок итератора (например, говорит, что в IEnumerable больше нет элементов).
с [+1] - хотя академически итераторов в .NET нет. только счетчики (в одном направлении, вперед.)
@Shaun Wilson, но с ключевым словом yield вы можете перебирать коллекцию в обоих направлениях, кроме того, вы можете брать каждый следующий элемент коллекции не подряд
@monstr вы можете перебирать сборку любым способом, и для этого вам не нужен yield. я не говорю, что вы ошибаетесь, я понимаю, что вы предлагаете; но академически в .NET нет итераторов, только счетчики (в одном направлении, вперед) - в отличие от stdC++, в CTS / CLR нет «общей структуры итераторов». LINQ помогает закрыть пробел с помощью методов расширения, которые используют yield returnа также методы обратного вызова, но они являются первоклассными методами расширения, а не первоклассными итераторами. результирующий IEnumerable не может сам выполнять итерацию в любом направлении, кроме как вперед по отношению к вызывающему.
Сообщает итератору, что он достиг конца.
Например:
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;
}
}
Он указывает, что итератор подошел к концу. Вы можете рассматривать 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");
В этом случае последний оператор никогда не выполняется, потому что мы преждевременно вышли из функции.
Может ли это быть просто break вместо yield break в вашем примере выше? Компилятор на это не жалуется.
@orad простой break в этом случае остановит цикл, но не прервет выполнение метода, таким образом, будет выполнена последняя строка и действительно будет виден текст «Не вижу меня».
@ DamirZekić, завершает ли итератор все циклы в случае обрыва?
@machinarium Я не уверен, что именно вы спрашиваете, но после yield break никакой другой код в итераторе выполняться не будет, поэтому дальнейших циклов не будет.
так что это когда мы не хотим условно пропускать оставшуюся доходность ...
@deadManN вы должны использовать yield break, чтобы безоговорочно пропустить оставшиеся yield return.
@Damir Zekić Не могли бы вы также добавить к своему ответу, почему вы должны предпочесть перерыв в доходности возврату и в чем их отличия?
@ DamirZekić возвращает null, а yield break не является то же самое. Если вы вернете значение null, вы можете получить NullReferenceException, получающий перечислитель IEnumerable, а с yield break вы этого не сделаете (есть экземпляр без элементов).
@BrunoCosta Попытка получить регулярные возвраты в том же методе приводит к ошибке компилятора. Использование yield return x предупреждает компилятор, что вы хотите, чтобы этот метод был синтаксическим сахаром для создания объекта Enumerator. Этот перечислитель имеет метод MoveNext() и свойство Current. MoveNext () выполняет метод до тех пор, пока не появится оператор yield return, и преобразует это значение в Current. В следующий раз, когда вызывается MoveNext, выполнение продолжается оттуда. yield break устанавливает для Current значение null, сигнализируя о конце этого перечислителя, так что foreach (var x in myEnum()) завершится.
@Wolfzoon Вместо того, чтобы видеть, что yield break устанавливает для Current значение nul, я вижу, что MoveNext возвращает false. Первый возвращает нулевое значение, второй - нет.
public IEnumerable<int> GetEnumerable() { ... }, а затем используйте его как foreach (var e in GetEnumerable()) { e.Dump(); }. Чтобы попробовать, см. DotNetFiddle.
Означает ли это, что yield return null; такой же, как yield break;?
yield в основном заставляет метод IEnumerable<T> вести себя аналогично кооперативному (в отличие от упреждающего) запланированному потоку.
yield return похож на поток, вызывающий функцию «расписания» или «сна», чтобы отказаться от управления процессором. Подобно потоку, метод IEnumerable<T> восстанавливает элементы управления в точке сразу после этого, при этом все локальные переменные имеют те же значения, что и до потери управления.
yield break подобен потоку, достигающему конца своей функции и завершающемуся.
Люди говорят о «конечном автомате», но конечный автомат - это на самом деле «поток». У потока есть некоторое состояние (т.е. значения локальных переменных), и каждый раз, когда он запланирован, он предпринимает некоторые действия, чтобы достичь нового состояния. Ключевым моментом в отношении yield является то, что, в отличие от потоков операционной системы, к которым мы привыкли, код, который его использует, замораживается во времени до тех пор, пока итерация не будет продвинута вручную или завершена вручную.
Здесь 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 попадает в метод, выполнение этого метода останавливается без возврата. Бывают ситуации, когда вы не хотите давать никакого результата, тогда вы можете использовать yield break.
Ключевое слово yield используется вместе с ключевым словом return для предоставления значения объекту перечислителя. доходность доходность определяет возвращаемое значение или значения. Когда достигается оператор yield 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.
Вы не объяснили, что делает yield break
Я не думаю, что yield return действительно поддерживает возврат нескольких значений. Может быть, вы на самом деле не это имели в виду, но я так прочитал.
Сэм - метод SampleNumbers с несколькими операторами yield return действительно работает, значение итератора возвращается немедленно, и выполнение возобновляется при запросе следующего значения. Я видел, как люди заканчивали такой метод "yield break", но в этом нет необходимости. Нажатие на конец метода также завершает итератор
Причина, по которой это плохой пример для yield break, заключается в том, что он не содержит перечислителя уровня языка, такого как foreach - при использовании перечислителя yield break предоставляет реальную ценность. этот пример выглядит как развернутый цикл. вы почти никогда не увидите этот код в реальном мире (конечно, мы все можем думать о некоторых крайних случаях), также здесь нет «итератора». «блок итератора» не может выходить за рамки метода в зависимости от языковой спецификации. то, что фактически возвращается, является «перечислимым», см. также: stackoverflow.com/questions/742497/…
Оператор 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(..).
yield break - это просто способ сказать return в последний раз и не возвращать никакого значения
например
// returns 1,2,3,4,5
IEnumerable<int> CountToFive()
{
yield return 1;
yield return 2;
yield return 3;
yield return 4;
yield return 5;
yield break;
yield return 6;
yield return 7;
yield return 8;
yield return 9;
}
Возврат доходности устраняет необходимость в списке поддержки, то есть вам не нужно кодировать что-то вроде
MyList.Add(...), просто выполнитеyield return .... Если вам нужно преждевременно выйти из цикла и вернуть список виртуальных резервных копий, вы используетеyield break;.