Какая польза от перерыва в доходности?

Возможный дубликат:
Что означает «yield break ; » сделать на C #?

Может ли кто-нибудь увидеть использование оператора yield break, которого нельзя было бы иначе достичь с помощью break или return.

Это утверждение кажется совершенно бесполезным. Более того, без этого оператора оператор yield return X можно было бы упростить до yield X, что гораздо удобнее для чтения.

Что мне не хватает?


person Community    schedule 31.01.2009    source источник


Ответы (6)


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

public IEnumerable<T> EnumerateThroughNull<T>(IEnumerable<T> source)
{
    if (source == null)
        yield break;

    foreach (T item in source)
        yield return item;
}

Без разрыва доходности невозможно вернуть пустой набор внутри итератора.

person Cameron MacFarland    schedule 31.01.2009
comment
@Cameron: спасибо за этот образец кода, он помог мне с проблемой, с которой я столкнулся! Престижность! - person p.campbell; 06.08.2009
comment
yield break возвращает пустой перечислимый ... по существу (в вашем случае) то же самое, что и return new T[0], но без создания пустого массива. - person ; 12.11.2009
comment
Что ж, мы могли бы просто заставить оператор if запускаться только в том случае, если source! = Null, но точка взята - person Casebash; 22.02.2010

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

Я не уверен, зачем также нужно ключевое слово return. Я предполагаю, что это поможет прояснить цель заявления.

Если вам интересно, в этой статье объясняется, что делает yield за кулисами.

За кулисами C # ключевое слово yield

person Bob    schedule 31.01.2009
comment
Я не так читаю поведение - «yield break» отменяет весь метод, ничего не возвращая. У вас может быть 10K элементов yield return (ed), но если затем выполняется «разрыв доходности» в том же методе, вы получите всего 0 элементов. - person Dave Swersky; 31.01.2009
comment
@ Дэйв: Я так не думаю ... как тогда ленивая оценка будет работать в блоке итератора? - person chakrit; 31.01.2009
comment
@Dave, нет, yield break останавливает возврат каких-либо элементов, но не отменяет (и не может) отменять уже возвращенные. - person configurator; 31.01.2009
comment
@Bob: возврат сам по себе не приведет к ошибке - он просто не будет компилироваться внутри блока итератора. Комбинация ключевых слов yield return необходима для предотвращения нарушения существующего кода. - person configurator; 31.01.2009
comment
@configurator, Майлз спросил, почему вы не можете использовать return сам по себе, если это разрешено, синтаксис может сбивать с толку, что может привести к ошибкам. - person Bob; 31.01.2009
comment
@ Дэйв, подумайте о ключевом слове break внутри for или foreach. Просто потому, что вы сломались, это не означает, что код будет выполнен до того, как он будет отменен. Когда вы выдаете возвращаемое значение, выполнение метода по существу приостанавливается и возобновляется, когда будет запрошен следующий элемент. - person Bob; 31.01.2009

yield break и break делают совершенно разные вещи! Смотреть

for(int i = 0; i < 10; ++i) {
   if(i > 5) { break; }
   yield return i;
}

for(int v = 2710; v < 2714; v+=2) {
   yield return v;
}

for(int s = 16; s < 147; ++s) {
   if(s == 27) { yield break; }
   else if(s > 17) { yield return s; }
}

Результатом будет IEnumerable этих значений: 0, 1, 2, 3, 4, 5, 2710, 2712, 18, 19, 20, 21, 22, 23, 24, 25, 26.

Вот метод, который не делает ничего полезного, но он показывает, что вы можете объединить yield break и break в один и тот же метод, и они делают две разные вещи! Break просто прерывает цикл, yield break полностью завершает метод.

Я предполагаю, что причина, по которой return не используется, заключается в том, что вы сами не возвращаете IEnumerable в методе. Кроме того, не кажется ли вам, что в такой итеративной ситуации разрыв yield яснее, чем return? Лично я.

person Ray Hidayat    schedule 31.01.2009
comment
lol ой ой, я не хотел, чтобы он это делал, я исправлю это. - person Ray Hidayat; 31.01.2009

Недопустимо использовать оператор return в блоке итератора. Более того, оператор break мог бы служить двойной цели в блоке итератора, если бы ему было разрешено влиять на итерацию: его можно было бы использовать для выхода из цикла или выхода из переключателя, и его можно было бы использовать для выхода из вся итерация.

yield return и yield break и сами по себе являются двумя ключевыми словами, и оба они кажутся необходимыми.

person yfeldblum    schedule 31.01.2009

Вам нужно различать возврат уже существующей реализации IEnumerable (возможно, вы собираетесь вернуть список) и анонимного итератора.

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

person casperOne    schedule 31.01.2009

Оператор return используется для возврата значения из функции.

Если у вас есть такая функция итератора:

public IEnumerable<int> IteratorOverInt() { }

оператор return в приведенной выше функции должен вернуть заполненный IEnumerable<int>.

public IEnumerable<int> IteratorOverInt() {
    return new List<int> { 1, 2, 3, 4 };
}

но если вы работаете с функцией итератора, вы будете использовать yield return, поэтому ваш код может выглядеть так:

public IEnumerable<int> IteratorOverInt() {
    for (int i = 0; i < 4; i++) {
        yield return i;
    }
}

Итак, yield return возвращает int, в то время как подпись метода требует IEnumerable<int>

Что будет делать оператор return в приведенном выше случае? Вернуть результаты, превосходящие урожайность? Связать все с урожайностью? return в приведенном выше случае не имеет особого смысла.

Таким образом, нам нужен способ return, который имеет смысл в блоке итератора, поэтому есть yield break.

Конечно, вы можете сделать это с break, но как бы тогда выйти из тела функции, если у вас есть еще код, который будет выполняться? Обернуть все в сложный блок if-else? Я бы сказал, что было бы лучше иметь yield break.

person chakrit    schedule 31.01.2009