C# Tutorial Lesson 23: Iterators [2.0]

Note: this lesson covers new functionality in C# 2.0, which at the time of writing is not released.

To understand iterators we first need to understand enumerators.

Enumerators are specialist objects which provide one with the means to move through an ordered list of items one at a time (the same kind of thing is sometimes called a 'cursor'). The .NET framework provides two important interfaces relating to enumerators: IEnumerator and IEnumerable. Objects which implement IEnumerator are themselves enumerators; they support the following members:

- the property Current, which points to a position on the list

- the method MoveNext, which moves the Current item one along the list

- the method Reset, which moves the Current item to its initial position (which is before the first item).

Objects which implement IEnumerable, on the other hand, merely contract to provide enumerators when a request is made to their GetEnumerator method (excitingly, an object that implements both of these interfaces can return itself from the GetEnumerator method!)

With the onset of Generics, there are now also the corresponding generic interfaces IEnumerator<T> and IEnumerable<T>.

The other fact worth mentioning is that the 'foreach' statement can be used to iterate through an IEnumerable or an IEnumerator instance. This is illustrated by the following code, which uses the ArrayList class (which implements IEnumerable).

1.

ArrayList arr = new ArrayList();

2.

arr.Add(obj1);

3.

arr.Add(obj2);

4.

    

5.

foreach (object o in arr)

6.

{

7.

    MessageBox.Show(o.ToString());

8.

}


The point of iterators is to allow the easy implementation of enumerators. Where a method needs to return either an enumerator or an enumerable class for an ordered list of items, it is written so as to return each item in its correct order using the 'yield' statement. The following code demonstrates this idea:

1.

public IEnumerable GetEnumerator()

2.

{

3.

    for (int x=0; x<itemArray.Length; x++)

4.

        yield return itemArray[x];

5.

}


Note that the code author doesn't create any enumerators or enumerables within the code; he just 'yields' the outputs in the required order and lets the compiler take care of generating the appropriate object.

In this example, the type of the objects listed by the generated enumerator is 'object'. Where one is using a generic interface like IEnumerable<T>, the type of the objects listed by the enumerator is 'T'.

Returning a subset of items

The example method given previously demonstrates the 'yield return' statement. There is also the 'yield break' statement, which is used to indicate that the last item has been yielded. This statement could be used to limit the number of items in the enumerator vended by the method, as in the following example (which lacks some basic checks on array sizes):

1.

public IEnumerable GetShortEnumerator(int l)

2.

{

3.

    for (int x=0; x<itemArray.Length; x++)

4.

    {

5.

        yield return itemArray[x];

6.

        if (x==l)

7.

            yield break;

8.

    }

9.

}


Link Building Information