Adding Multiple Iterators on a Single Type




Adding Multiple Iterators on a Single Type

Problem

You need to add an iterator to a type that already implements the GetEnumerator iterator method; however, the iterators that you need to add are simple enough that they do not require parameters to be passed in to them as in Recipe 6.5. for example, the existing GetEnumerator iterator yields all elements in a forward-only order, but you also need to add an iterator that yields all elements in reverse order, an iterator that yields only the first half of the elements, and one that yields only the second half of the elements.

Solution

To add simple iterators that do not require parameters to be passed in to them, you can add properties with a get accessor. The get accessor must return an IEnumerable type and make use of the yield return statement. Figure shows one way to implement the solution.

Adding multiple iterators that do not require parameters on a single type

public class SimpleListIterator
{
    private List<string> _items = new List<string>();
    
    public void AddItem(string item)
    {
        _items.Add(item);
    }

    public IEnumerator GetEnumerator()
    {
        for (int index = 0; index < _items.Count; index++)
        {
            yield return (_items[index]);
        }
    }

    // Additional iterators implemented as property get accessors
    public IEnumerable ReverseOrder
    {
        get
        {
            for (int index = _items.Count - 1; index >= 0; index--)
            {
                yield return (_items[index]);
            }
        }
    }

    public IEnumerable FirstHalf
    {
        get
        {
            for (int index = 0; index < (_items.Count / 2); index++)
            {
                yield return (_items[index]);
            }
        }
    }

    public IEnumerable SecondHalf
    {
        get
        {
            for (int index = (_items.Count / 2); index < _items.Count; index++)
            {
                yield return (_items[index]);
            }
        }
    }
}

Discussion

The SimpleListIterator class contains the typical GetEnumerator iterator method that yields all items in the _items list. In addition to this iterator method, the class contains three additional iterators: ReverseOrder, FirstHalf, and SecondHalf. The ReverseOrder iterator simply yields the elements in the _items list in reverse-index order, whereas the GetEnumerator method yields all elements in forward-index order. This is accomplished by setting up a for loop to start at either the zeroth element, for the GetEnumerator iterator method, or at the last element, as with the ReverseOrder iterator property.

The FirstHalf iterator property starts at the zeroth index of the _items list and yields all elements in the list up to the middle index. At this point iteration stops. The SecondHalf iterator property starts where the FirstHalf iterator property left off and continues yielding elements of the _items list until the end of this list.

The following code shows how the GetEnumerator iterator method is used, as well as the three iterator properties:

	public static void TestIteratorProperties()
	{
	    //Create SimpleListIterator object and fill it with data.
	    SimpleListIterator b = new SimpleListIterator();
	    b.AddItem("item1");
	    b.AddItem("item2");
	    b.AddItem("item3");
	    b.AddItem("item4");
	    b.AddItem("item5");
	    b.AddItem("item6");
	    b.AddItem("item7");

	    // Display all data in SimpleListIterator object.
	    Console.WriteLine("\r\nGetEnumerator iterator");
	    foreach (string s in b)
	    {
	        Console.WriteLine(s);
	    }

	    Console.WriteLine("\r\nReverseOrder iterator");
	    foreach (string s in b.ReverseOrder)
	    {
	        Console.WriteLine(s);
	    }

	    Console.WriteLine("\r\nFirstHalf iterator");
	    foreach (string s in b.FirstHalf)
	    {
	        Console.WriteLine(s);
	    }

	    Console.WriteLine("\r\nSecondHalf iterator");
	    foreach (string s in b.SecondHalf)
	    {
	        Console.WriteLine(s);
	    }
	}

This code produces the following output:

	GetEnumerator iterator
	item1
	item2
	item3
	item4
	item5
	item6
	item7

	ReverseOrder iterator
	item7
	item6
	item5
	item4
	item3
	item2
	item1

	FirstHalf iterator
	item1
	item2
	item3

	SecondHalf iterator
	item4
	item5
	item6
	item7

Notice that when using the GetEnumerator iterator, the foreach loop is set up as a typical foreach loop. However, when one of the iterator properties is used, the foreach loop is set up slightly differently. In this case, the iterator property's get accessor is actually called.

	foreach (string s in b.ReverseOrder)

The iterator property returns an IEnumerable, which in turn is used by the foreach loop to obtain an IEnumerator.

See Also

See the "Iterators," "IEnumerator Interface," and "IEnumerable Interface" topics in the MSDN documentation.