C# Enumerators


This entry is part 5 of 7 in the series C# Generics

To understand enumerators, we’ll first look at C# arrays. This is for your understanding of enumerators. Generally you will be working with generic enumeration interfaces.

You can use a foreach statement to cycle through the elements of an array. When you use a foreach statement with an array, the statement presents you with each element in the array, one by one, allowing you to read its value. Why does this work with arrays? The reason is that an array can produce, upon request, an object called an enumerator. The enumerator is an object that can return the elements of the array, one by one, in order, as they’re requested. The enumerator “knows” the order of the items and keeps track of where it is in the sequence. It then returns the current item when it is requested. For example, the following code declares an array with four elements and then uses a foreach loop to print out the values of the items:

using System;
namespace EnumeratorsIllustrated
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] arr1 = { 10, 11, 12, 13 }; // Define the array.
            foreach (int item in arr1) // Enumerate the elements.
                Console.WriteLine($"Item value: { item }");
        }
    }
}

Enumerable types

Enumerable types are sometimes just called enumerables. Arrays are enumerables. For a type that has an enumerator, there must be a way of retrieving it. The way to retrieve an object’s enumerator is to call the object’s GetEnumerator method. Types that implement a GetEnumerator method are enumerable types.

The foreach construct is designed to work with enumerables. As long as the object it’s given to iterate over is an enumerable type, such as an array, it performs the following actions: (1) It gets the object’s enumerator by calling its GetEnumerator method (2) It requests each item from the enumerator and makes it available to your code as the iteration variable, which your code can read (but not change).

The IEnumerator Interface

The IEnumerator supports a simple iteration over a non-generic collection. An enumerator implements the IEnumerator interface, which contains three function members: Current (property), MoveNext (method), and Reset (method). An explanation of each of these three is on page 488 of the book Illustrated C# 7: The C# Language Presented Clearly, Concisely, and Visually 5th Edition by Daniel Solis (Author), Cal Schrotenboer (Author).

The way the enumerator keeps track of the current item in the sequence is entirely implementation dependent. It might be implemented as a reference to an object, an index value, or something else entirely. In the case of the built-in single-dimensional array type, it’s simply the index of the item.

Simulate a foreach Loop

Given a collection’s enumerator, you should be able to simulate a foreach loop by cycling through the items in the collection using the MoveNext and Current members. For example, you know that arrays are enumerable, so the following code does manually what the foreach statement does automatically. In fact, the C# compiler generates code similar to this (in CIL, of course) when you write a foreach loop.

using System;
using System.Collections;
using System.Collections.Generic; // do not need this here
namespace EnumeratorsIllustrated
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] arr1 = { 10, 11, 12, 13 }; // Create an array.
            IEnumerator ie = arr1.GetEnumerator(); // Get and store the enumerator.
            while (ie.MoveNext()) // Move to the next position.
            {
                int item = (int)ie.Current; // Get the current item.
                Console.WriteLine($"Item value: { item }"); // Write it out.
            }
        }
    }
}

The IEnumerable Interface

An enumerable class is one that implements the IEnumerable interface. The IEnumerable interface has only a single member, method GetEnumerator, which returns an enumerator for the object. The GetEnumerator method returns an enumerator object for the class. The following code gives an example of an enumerable class that uses an enumerator class called ColorEnumerator, which implements IEnumerator. We’ll show the implementation of ColorEnumerator in the next section.

using System.Collections;
class MyColors: IEnumerable
   {
   string[] Colors = { "Red", "Yellow", "Blue" };
   public IEnumerator GetEnumerator()
   {
      return new ColorEnumerator(Colors);
   }
}

Example using IEnumerable and IEnumerator

The following code shows a full example of an enumerable class called Spectrum and its enumerator class ColorEnumerator. Class Program creates an instance of MyColors in method Main and uses it in a foreach loop.

using System;
using System.Collections;
using System.Collections.Generic; // do not need this here
namespace EnumeratorsIllustrated
{
    class Program
    {
        static void Main()
        {
            Spectrum spectrum = new Spectrum();
            foreach (string color in spectrum) Console.WriteLine(color);
        }
    }
    class ColorEnumerator : IEnumerator
    {
        string[] Colors;
        int Position = -1;
        public ColorEnumerator(string[] theColors) // Constructor
        {
            Colors = new string[theColors.Length];
            for (int i = 0; i < theColors.Length; i++)
                Colors[i] = theColors[i];
        }
        public object Current // Implement Current.
        {
            get
            {
                if (Position == -1)
                    throw new InvalidOperationException();
                if (Position >= Colors.Length)
                    throw new InvalidOperationException();
                return Colors[Position];
            }
        }
        public bool MoveNext() // Implement MoveNext.
        {
            if (Position < Colors.Length - 1)
            {
                Position++;
                return true;
            }
            else
                return false;
        }
        public void Reset() // Implement Reset.
        {
            Position = -1;
        }
    }
    class Spectrum : IEnumerable
    {
        string[] Colors = { "violet", "blue", "cyan", "green", "yellow", "orange", "red" };
        public IEnumerator GetEnumerator()
        {
            return new ColorEnumerator(Colors);
        }
    }
}

This code produces the following output:

violet
blue
cyan
green
yellow
orange
red
Press any key to continue . . .
Series Navigation<< C# Generic MethodsC# Generic Enumeration Interfaces >>