2017-02-14 14 views
2

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

public IEnumerator Test() 
{ 
} 

Дает ошибку:

Error CS0161 'Test.GetEnumerator()': not all code paths return a value

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

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

нет? (и работает так, как ожидалось, сначала MoveNext() возвращает false)

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

+1

Вы также можете использовать 'yield break;' вместо оператора dummy if. –

ответ

3

От C# спецификации:

A block that contains one or more yield statements (§8.14) is called an iterator block. Iterator blocks are used to implement function members as iterators (§10.14).

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

0

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

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

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