Почему IEnumerator должен иметь хотя бы один оператор yield, даже если он недоступен?

Почему этот код:

public IEnumerator Test()
{
}

Выдает вам ошибку:

Ошибка CS0161 «Test.GetEnumerator()»: не все пути кода возвращают значение

Однако этот код:

public IEnumerator Test()
{
    if(false)
        yield return 0;
}

Нет? (и работает как положено; первый MoveNext() возвращает false)

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


person splattru    schedule 14.02.2017    source источник
comment
Вы также можете использовать yield break; вместо фиктивного оператора if.   -  person Mike Zboray    schedule 15.02.2017


Ответы (2)


Из спецификации С#:

Блок, содержащий один или несколько операторов yield (§8.14), называется блоком итератора. Блоки итераторов используются для реализации функций-членов в качестве итераторов (§10.14).

Итак, если у вас есть один или несколько операторов yield, независимо от того, достижимы они или нет, ваш метод — это итератор (внутри которого будет генерироваться класс итератора). Но если у вас нет операторов yield, ваш метод является порядковым методом (не итератором), который имеет возвращаемое значение типа IEnumerable. Как и любой другой метод, который возвращает какое-то значение, вы должны либо вернуть значение требуемого типа, либо выдать исключение из тела метода. Те же правила применяются, когда у вас есть метод, который возвращает значение string или int.

person Sergey Berezovskiy    schedule 14.02.2017

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

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

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

person Servy    schedule 14.02.2017