Women in Technology

Hear us Roar



Article:
  C# Iterators
Subject:   Each call to GetEnumerator?
Date:   2006-12-09 02:31:35
From:   jammaj
"""The GetEnumerator method makes use of the new yield statement. A yield statement returns an expression. The yield statement appears only inside an iterator block and returns the value that is expected by the calling foreach statement. That is, each call to GetEnumerator will yield the next string in the collection; all the state management is done for you!"""


This explanation of yield seems confused. The foreach statement isn't calling GetEnumerator repeatedly to get the next value, based on the type signature of GetEnumerator it'd be creating a new enumerator each time it did... and indeed the following example confirms that the yield statement bottles up the state of the method halting execution of the method in between MoveNext calls:



using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;


namespace EnumTest
{
class Enumr : IEnumerable<int>
{
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }


public IEnumerator<int> GetEnumerator()
{
yield return 123;
yield return 456;
yield return 789;
}
}


class Program
{
static void Main(string[] args)
{
Enumr enumr = new Enumr();


IEnumerator<int> enum1 = enumr.GetEnumerator();
IEnumerator<int> enum2 = enumr.GetEnumerator();


enum1.MoveNext();
enum1.MoveNext();
Console.WriteLine(enum1.Current); // Outputs 456


enum2.MoveNext();
Console.WriteLine(enum2.Current); // Outputs 123
}
}
}


Furthermore, the yield statement seems directly stolen from Python's "generators" which do the same thing:



def make_generator():
yield 213
yield 456
yield 789


for X in make_generator():
print X


...is equivalent to the C# code above.