CSharp - Implementing the Enumeration Interfaces

Introduction

You implement IEnumerable or IEnumerable<T> for one or more of the following reasons:

  • To support the foreach statement
  • To work with a standard collection
  • To meet the requirements of a collection interface
  • To support collection initializers

To implement IEnumerable/IEnumerable<T>, you must provide an enumerator.

You can do this in one of three ways:

  • If the class is "wrapping" another collection, by returning the wrapped collection's enumerator
  • Via an iterator using yield return
  • By instantiating your own IEnumerator/IEnumerator<T> implementation

Here's a simple example:

class MyCollection : IEnumerable
{
    int[] data = { 1, 2, 3 };

    public IEnumerator GetEnumerator()
    {
         foreach (int i in data)
           yield return i;
    }
}

GetEnumerator doesn't appear to return an enumerator.

C# compiler converts the yield return statement to nested enumerator class, and then refactors GetEnumerator to instantiate and return that class.

You can also implement the generic interface IEnumerable<T>:

class MyGenCollection : IEnumerable<int>
{
       int[] data = { 1, 2, 3 };

       public IEnumerator<int> GetEnumerator()
       {
         foreach (int i in data)
           yield return i;
       }

       IEnumerator IEnumerable.GetEnumerator()     // Explicit implementation
       {                                           // keeps it hidden.
         return GetEnumerator();
       }
}

Rather than writing a class, you can move the iteration logic into a method returning a generic IEnumerable<T> and let the compiler take care of the rest.

Here's an example:

class Test
{
       public static IEnumerable <int> GetSomeIntegers()
       {
         yield return 1;
         yield return 2;
         yield return 3;
       }
}

Here's our method in use:

foreach (int i in Test.GetSomeIntegers())
       Console.WriteLine (i);

Related Topic