Why does this code:
public IEnumerator Test()
{
}
Gives you an error:
Error CS0161 'Test.GetEnumerator()': not all code paths return a value
However this code:
public IEnumerator Test()
{
if(false)
yield return 0;
}
Doesn't? (and works as expected; first MoveNext() returns false)
When using IEnumerators as coroutines, sometimes you want to make a coroutine (IEnumerator) that doesn't have an async operations yet (is not yielding anything) but might do that in future.
If there aren't any
yield
statements in the method block at all, then it's not an iterator block and the compiler has no idea that you want to perform the relevant transformations on it. It's going to treat it just like any other method where you return a value.The compiler team could have done what they did with
async
and added a new keyword to the signature of the method, which, if present, made the method an iterator block, allowedyield
statements in the body, and would allow an empty body to be treated as yielding nothing, but they chose not to.If there is a
yield
statement in the method body somewhere there isn't actually any need for one to reliably be hit for the method to properly compile and run. In an iterator block hitting the end of the method means the sequence is over, even if no items have yet been yielded, which is an entirely sensible behavior. The method still has anIEnumerable
orIEnumerator
to return, it just has no values to yield.From C# specification:
So if you have one or more yield statements, no matter reachable or not, your method is iterator (under the hood that will generate iterator class). But if you don't have any yield statements your method is the ordinal method (not an iterator) which has a return value of
IEnumerable
type. As any other method which returns some value, you must either return value of required type or throw an exception from method body. Same rules are applied when you have method which returnsstring
orint
value.