#1,117 – foreach Requires IEnumerable Implementation

The foreach statement works on an object that implements IEnumerable<T> or IEnumerable.  It also works on an object whose type has a public GetEnumerator method that returns an IEnumerator<T> or IEnumerator.

Below, we’ve defined a new class that implements IEnumerable<T>.

    public class DogPack : IEnumerable<Dog>
    {
        private List<Dog> thePack;

        public DogPack()
        {
            thePack = new List<Dog>();
        }

        public void Add(Dog d)
        {
            thePack.Add(d);
        }

        // Remove arbitrary dog
        public void Cull()
        {
            if (thePack.Count == 0)
                return;

            if (thePack.Count == 1)
                thePack.RemoveAt(0);
            else
            {
                Random rnd1 = new Random();
                int indRemove = rnd1.Next(thePack.Count);
                thePack.RemoveAt(indRemove);
            }
        }

        // IEnumerable<T> implementation

        public IEnumerator<Dog> GetEnumerator()
        {
            return thePack.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }

We can now use foreach to iterate on an instance of this class.

            DogPack pack = new DogPack();
            pack.Add(new Dog("Lassie", 8));
            pack.Add(new Dog("Shep", 12));
            pack.Add(new Dog("Kirby", 10));
            pack.Add(new Dog("Jack", 15));
            pack.Cull();

            // Who's left?
            foreach (Dog d in pack)
                Console.WriteLine(d);

1117-001

#1,068 – Generic IEnumerable Interface Is Covariant

A covariant generic interface is one that allows an assignment from a constructed version of the interface on a derived class to a constructed version of the interface for a base class.

For example:

            // If herders is (or implements) IFirstAndLast<BorderCollie>:
            IFirstAndLast<Dog> dogLine = herders;

The IEnumerable<T> interface in System.Collections.Generic is covariant.  This means that you can assign a collection of a given type to an IEnumerable<T> where the represents a type further up the inheritance chain.

For example:

            List<BorderCollie> someBCs = new List<BorderCollie> {
                new BorderCollie("Shep"),
                new BorderCollie("Kirby")
            };

            // Because BorderCollie derives from Dog,
            // we can do the following
            IEnumerable<Dog> dogList = someBCs;

If MerleBorderCollie inherits from BorderCollie, which in turn inherits from Dog, we can also do:

            List<MerleBorderCollie> merles = new List<MerleBorderCollie>
            {
                new MerleBorderCollie("Lady")
            };
            IEnumerable<Dog> moredogs = merles;

#600 – Reversing the Elements in an Array

You can use the static Array.Reverse method to reverse the order of elements in an array.  This modifies the contents of the array that you pass to Array.Reverse.

            int[] someNumbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
            DumpArrayContents(someNumbers);

            // Reverse the elements using Array.Reverse
            Array.Reverse(someNumbers);
            DumpArrayContents(someNumbers);

Note that this Reverse method is different from the IEnumerable<int>.Reverse method, which does not modify the contents of the array, but just returns a reversed sequence.

// IEnumerable<int>.Reverse
int[] moreNumbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
IEnumerable<int> reversedNums = moreNumbers.Reverse();
DumpArrayContents(moreNumbers);
DumpArrayContents(reversedNums);

#563 – Enumerable Types Can Generate Multiple Enumerators

Each time that the GetEnumerator method in an enumerable type is called, an independent enumerator is generated.  Each enumerator keeps track of its own position in the parent sequence.

In the example below, nested foreach statements each iterate over the same collection.  The outer foreach statement results in one enumerator and the inner foreach statement results in the generation of a new enumerator for each pass of the outer foreach.

In this case, the ability to generate multiple independent enumerators is necessary, so that we can have overlapping foreach statements.

            int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

            foreach (int i in nums)
                foreach (int j in nums)
                    Console.WriteLine("{0} x {1} = {2}", i, j, i * j);

#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.

 

#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.