Yield Return

Even though the yield return statement was added to C# since version 2.0 (around 2004) I never quite understood how it really works. A few days ago while going through some tutorials I saw a sample of code that used yield return and decided to finally look under the covers and learn how it works.

How well do you understand yield return? Look at the code below and answer these two questions:

class YieldSample
{
  static void Main(string[] args)
  {
    foreach (int i in YieldSample.GetSomeIntegers())
    {
      Console.WriteLine("{0}", i);
    }
    Console.ReadLine();
  }
  public static IEnumerable GetSomeIntegers()
  {
    yield return 100;
    yield return 200;
    yield return 300;
  }
}

The answer to the first question is pretty simple: 100, 200, and 300.

The tricky part is explaining how come C# arrives to this output. How come C# knows that it needs to pick up the first value (100) in the first loop, 200 in the second, and 300 in the third one?

The reason for this behavior is that at compile time C# rewrites the code with the yield return into a state machine that has the logic to return the first value and prepare the code so that in the second call it picks up the second value, and so on and so forth. The pseudo-code for the generated code basically looks like this: 

private bool GetNextElement()
{
  switch ( state )
  {
    case 0:         // first state of the machine
      currentValue = 100;
      state = 1; // prepare machine for next state
      return true;
    case  1:       // second state of the machine
      currentValue = 200
      state = 2; // prepare machine for next state
      return true;
    case   2:     // third state of the machine
      currentValue = 300;
      state = 3; // prepare machine for next state
      return true;
    case   3: 
      state = -1
      return false;
   }
}

While trying to understand how the yield return statement works I found two great articles that explain this in more detail. In particularly I liked Yield, and the C# state machine by Erik Forbes and C#: Dynamic Iterators with Yield Return by Paul Kimmel. These two articles actually gave me the clue to use Reflector to look at the code generated by the compiler. 

If you are like me you are probably wondering how well this code generation works when the method is not as straightforward as this little example that just returns three hard coded values. The answer is pretty darn good. State machines have been studied by a lot of people and very well understood.

However, just for fun I wrote a few examples of my own with if and nested if statements around the yield return and reviewed the code that the compiler generated. The result was always the same: the resulting code returned the values as expected.

Blog posted on: 2010-04-02T03:59:53.744Z