Implementing the generic IEnumerable interface

Say you want to implement a class that implements the IEnumerable interface in C#. Then you have two choices, either to implement the old-style non-generic IEnumerable interface or you can implements the generic IEnumerable<T> interface. Given those choices we of course want to implement the new generic version of the interface. Because otherwise lots of boxing and unboxing will happen when T is a value type, with the non-generic version you will not be able to conveniently use the Current property of your enumerator, and for general type-safety goodness.

Thus, you set out to implement the generic version. For example, let say we want to implement a class that enumerates all the integers staring from a given offset. First we might try this:

using System.Collections.Generic;
class Ints : IEnumerable<int> {
    private readonly int offset;
    public Ints(int o) { offset = o; }
    public IEnumerator<int> GetEnumerator() {
        int i = offset;
        while( true ) yield return i++;
    }
}

But then the compiler complains:

error CS0535: 'Ints' does not implement interface member 'System.Collections.IEnumerable.GetEnumerator()'

Thank you for letting us know nice compiler. But we don’t want Ints to implement the non-generic interface. We want it to implement the generic interface.

Reading up on the documentation will reveal that the generic interface inherits from the non-generic interface. What a wonderful design. Thankfully we can make a general work-around for this design flaw in the library. Just add a non-generic method that calls the generic method:

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

Once the author of my favorite C# book returns from vacation. I’ll complain to him that the section about IEnumerable didn’t make it clear that if you want to implement the generic interface you also have to implement the non-generic interface.

Update: It turns out that the errata to C# Precisely already mentions this curriousity.

11 thoughts on “Implementing the generic IEnumerable interface

  1. hey! thanks for this. ive been tearing my hair out trying to figure out whats going on here. didnt make any sense AT all. some of these little nuances can drive you nuts.

  2. Interesting. I originally got the same compiler error (does not implement interface member ‘System.Collections.IEnumerable.GetEnumerator()’). I then inserted the non-generic method call. Now the compiler error says I’m not implementing IEnumerable.GetEnumerator(). That method, of course, has been in the class all along (and it is public).The difference here is that my class (that implements IEnumerable) is also generic. In any case, I still don’t know what I should do.

  3. Rubio:

    Is it possible for you to post a minimal example showing the error. Similar to the Ints example in the post?

    For example, here is a generic repeater class. That is, when you construct the class you give it an element to repeat and how many times it should be repeated.

    using System;
    using System.Collections.Generic;
    
    class Repeater<T> : IEnumerable<T> {
      private readonly T elem;
      private readonly int no_of_times;
      public Repeater(int no, T e) { no_of_times = no; elem = e; }
      public IEnumerator<T> GetEnumerator() {
        for(int i = 0; i < no_of_times; ++i)
          yield return elem;
      }
      System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
        return GetEnumerator();
      }
    }
    
    class MainClass {
      public static void Main(string[] args) {
         Repeater<string> hellos = new Repeater<string>(10, "Hello");
         foreach (string s in hellos)
            Console.WriteLine(s);
      }
    }
    

  4. Why is it that when I Google topics like these I have to go through 2 to 7 pages worth of nonsense and people who don’t know what they are talking about before I find something useful like this? seems like most the pages are on the proper syntax of the for-each loop not how to implement the interface correctly.

Leave a Reply

Your email address will not be published. Required fields are marked *