Search code examples
c#yield-return

Yield return and "not all code paths return value"


Why the following code:

private static IEnumerable<int> TestYield(bool check)
{
    if (check)
    {
        return 1;
    }
    else
    {
        Console.WriteLine("In the else");
    }
}

produces an error with "not all code paths return value". However, the following code does not produce the same error:

private static IEnumerable<int> TestYield(bool check)
{
    if (check)
    {
        yield return 1;
    }
    else
    {
        Console.WriteLine("In the else");
    }
}

The only difference is the yield. What yield is making different that does not cause the same error?


Solution

  • When you use just return, because of your else statement does not return any thing, it gives you the error you mention and because you return int type it also gives the error "can not convert expression type int to return type IEnumerable".

    When you use yield return, under the covers the yield keyword creates a state machine to maintain state information. According to MSDN : "When a yield return statement is reached in the iterator method, expression is returned, and the current location in code is retained. Execution is restarted from that location the next time that the iterator function is called."

    Now for your question "what happens in the else side" I took a look generated IL code with ILSpy. I created a class named YTest and added method which returns with yield. Here is the generated code :

    internal class YTest
    {
        [IteratorStateMachine(typeof(YTest.<TestYield>d__0))]
        public static IEnumerable<int> TestYield(bool check)
        {
            int num;
            while (num == 0)
            {
                if (!check)
                {
                    Console.WriteLine("In the else");
                    IL_52:
                    yield break;
                }
                yield return 1;
            }
            if (num != 1)
            {
                yield break;
            }
            goto IL_52;
        }
    }
    

    Compiler adds yield break statement under the hood.

    When working with the yield keyword, you should keep these points in mind (besides msdn, quotes from https://www.infoworld.com/article/3122592/application-development/my-two-cents-on-the-yield-keyword-in-c.html

    ):

    • You cannot have the yield return statement in a try-catch block though you can have it inside a try-finally block

    • You cannot have the yield break statement inside a finally block

    • The return type of the method where yield has been used, should be IEnumerable, IEnumerable, IEnumerator, or IEnumerator

    • You cannot have a ref or out parameter in your method in which yield has been used

    • You cannot use the "yield return" or the "yield break" statements inside anonymous methods

    • You cannot use the "yield return" or the "yield break" statements inside "unsafe" methods, i.e., methods that are marked with the
      "unsafe" keyword to denote an unsafe context