
.NET 2.0+C# Iterators (2)
C# 2.0 introduced iterators. Iterators can be added to a class to allow traversing of a sequence of values with the foreach command. Although possible in earlier language versions, iterators remove the need to manually implement the IEnumerable interface.
The Yield Keyword
The key to C# 2.0 iterators is the yield keyword. Within the iterator block, in this case the GetEnumerator method, the yield return statement is used to return each of the items in the sequence. Often, the yield return statement appears in a loop but it is quite acceptable to provide a series of yield return statements with no loop present, or to create several loops to be executed one after the other.
When the yield return statement is executed, the specified value is returned to the calling statement and the state of the iterator is stored. When the next item in the sequence is requested, the code execution continues from the previous position. It is important to understand that the enumerator method is not executed in full each time.
In our example, the list of fruits will be returned in order. We can therefore use a for-loop to process the array. Add the following loop within the GetEnumerator method. NB: This is a simple example for demonstration purposes only. It is unlikely, though not impossible, that you would need to implement such a simple iterator as the array already supports the IEnumerable interface.
for (int i = 0; i < _fruitList.Length; i++)
{
yield return _fruitList[i];
}
When a foreach loop is executed against the class, the first iteration of the loop will execute the GetEnumerator method. This will initialise the for-loop before yielding the first result. On the second iteration of the foreach loop, the for-loop will not be re-initialised. The iterator will have stored its own state and will know that it should continue with the second iteration of the for-loop. This process continues until the for-loop is exhausted. The calling foreach loop is then terminated.
Before we can test the new iterator, we need to implement another method. As we decided to implement the IEnumerable<T> interface, we must also add the members of IEnumerable. This means creating a non-generic GetEnumerator method. We could include the same loop and yield statements in this loop. However, rather than repeating ourselves, this method can simply return the results of the existing version:
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
IEnumerator is defined in the System.Collections namespace, so add the following using directive to the code:
using System.Collections;
Executing the Iterator
Now that the iterators are defined, we can traverse the class' values with a simple foreach loop. In the following sample, a new object is created and used as the target for a loop. Try executing the sample to see the results. It is also worthwhile stepping through the code using the Visual Studio debugger in order to see the operation of the iterator.
MyEnumerableClass mec = new MyEnumerableClass();
foreach (string fruit in mec)
Console.WriteLine(fruit);
/* OUTPUT
Apple
Banana
Clementine
Damson
Elderberry
Fig
Grape
Huckleberry
Indian Prune
Jujube
Kiwi
Lime
*/
4 December 2008