#560 – Returning an Enumerator from an Iterator

You can return an enumerator from an iterator block.  This is something that you’d typically do when implementing your own collection class.

Below, we implement the DogsAndCows collection class, which manages a group of Dog and Cow objects.  It implements the IEnumerable interface, which means that it implements the GetEnumerator method, allowing iterating through the entire collection.

GetEnumerator uses an iterator block to return the enumerator.

    // Collection of dogs and cows
    public class DogsAndCows : IEnumerable
    {
        private List<Dog> theDogs = new List<Dog>();
        private List<Cow> theCows = new List<Cow>();

        public void AddDog(Dog d)
        {
            theDogs.Add(d);
        }

        public void AddCow(Cow c)
        {
            theCows.Add(c);
        }

        // Return first the dogs and then the cows
        public IEnumerator GetEnumerator()
        {
            foreach (Dog d in theDogs)
                yield return d;

            foreach (Cow c in theCows)
                yield return c;
        }
    }

We can iterate through this collection with foreach.

            foreach (IAnimal animal in oddPack)
                Console.WriteLine(animal.Name);

#559 – An Iterator Can Return an Enumerable Type or an Enumerator

An iterator is a block of code that contains one or more yield statements.  It can return one of the following interfaces:

  • IEnumerable  (in System.Collections)
  • IEnumerable<T>  (in System.Collections.Generic)
  • IEnumerator  (in System.Collections)
  • IEnumerator<T>  (in System.Collections.Generic)

You’d return an enumerable type when you want provide client code with a collection of objects and you don’t want to write your own custom collection class.

You’d typically return an enumerator when you’re implementing the GetEnumerator method in a custom collection class.

 

#558 – Using an Iterator Within a for Loop

An iterator block could contain a series of yield statements to return individual elements of a sequence.

        private static IEnumerable<Dog> ListOfDogs()
        {
            yield return new Dog("Jack", 17);
            yield return new Dog("Kirby", 14);
            yield return new Dog("Lassie", 72);
        }

More commonly, however, an iterator block will contain a loop that generates a sequence, with a yield statement that returns a new element of the sequence each time through the loop.

The example below returns a portion of the Fibonacci sequence, with each element in the sequence after the first two returned by a yield statement within the loop.

        static void Main()
        {
            foreach (int i in Fibonacci(20))
                Console.WriteLine(i);
        }

        private static IEnumerable<int> Fibonacci(int numInSeq)
        {
            yield return 0;
            yield return 1;

            int last = 0;
            int current = 1;

            for (int i = 0; i < (numInSeq - 2); i++)
            {
                int next = last + current;
                yield return next;
                last = current;
                current = next;
            }
        }

#557 – Using an Iterator to Return the Elements of an Enumerable Type

An iterator is a block of code that produces an enumerator.  (An enumerator is an object that knows how to move through a sequence of elements, typically implemented in an enumerable type that represents a collection of elements).

You can think of the iterator as the code that generates an enumerator, whereas a foreach loop is the code that makes use of the enumerator.

An iterator block is a block of code that includes one or more yield statements, each of which returns the next item in the sequence.  The iterator block can return either an enumerable type or an enumerator.  In the example below, the enumerable type IEnumerable<Dog> is returned.

        static void Main()
        {
            foreach (Dog d in ListOfDogs())
                Console.WriteLine(d.Name);
        }

        private static IEnumerable<Dog> ListOfDogs()
        {
            yield return new Dog("Jack", 17);
            yield return new Dog("Kirby", 14);
            yield return new Dog("Lassie", 72);
            yield return new Dog("Rin Tin Tin", 94);
        }

#556 – Using an Enumerator Explicitly

An enumerator is an object that knows how to move through a sequence of elements.  In C#, the foreach statement provides this same functionality wrapping an enumerator.

You can use an enumerator to iterate through a collection, rather than a foreach statement.  This helps in understanding how enumerators work.

The code fragment below shows iterating through a collection using the foreach statement and then doing the same thing using an enumerator.  (dogs is of type List<Dog>).

            // Using foreach
            foreach (Dog d in dogs)
                Console.WriteLine(d.Name);

            // Using enumerator directly
            List<Dog>.Enumerator dogEnum = dogs.GetEnumerator();
            while (dogEnum.MoveNext())
            {
                Dog d = (Dog)dogEnum.Current;
                Console.WriteLine(d.Name);
            }

The enumerator is an object of type List<T>.Enumerator.  We call a method on the List<T> object to get an instance of its enumerator and then navigate through the list using the MoveNext method.  The Current property returns the object that the enumerator is currently pointing to.

#555 – Enumerable Objects and Enumerators

An enumerable object is a type that represents a sequence of elements.  The type implements either the IEnumerable or IEnumerable<T> interface, which means that it implements a GetEnumerator method, which is called to get the enumerator for the enumerable class.

An enumerator is an object that knows how to move through a sequence of elements.  It implements either the IEnumerator or IEnumerator<T> interface, which means that it exposes a Current property that points to the current element in the sequence and a MoveNext method that moves to the next element.

You can think of an enumerator as a sort of pointer into a sequence of elements.

Enumerators, used on enumerable objects, are the internal mechanism that allows using a foreach statement to iterate through a collection of items.