174

I know how to implement the non generic IEnumerable, like this:

using System;
using System.Collections;

namespace ConsoleApplication33
{
    class Program
    {
        static void Main(string[] args)
        {
            MyObjects myObjects = new MyObjects();
            myObjects[0] = new MyObject() { Foo = "Hello", Bar = 1 };
            myObjects[1] = new MyObject() { Foo = "World", Bar = 2 };

            foreach (MyObject x in myObjects)
            {
                Console.WriteLine(x.Foo);
                Console.WriteLine(x.Bar);
            }

            Console.ReadLine();
        }
    }

    class MyObject
    {
        public string Foo { get; set; }
        public int Bar { get; set; }
    }

    class MyObjects : IEnumerable
    {
        ArrayList mylist = new ArrayList();

        public MyObject this[int index]
        {
            get { return (MyObject)mylist[index]; }
            set { mylist.Insert(index, value); }
        }

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

However I also notice that IEnumerable has a generic version, IEnumerable<T>, but I can't figure out how to implement it.

If I add using System.Collections.Generic; to my using directives, and then change:

class MyObjects : IEnumerable

to:

class MyObjects : IEnumerable<MyObject>

And then right click on IEnumerable<MyObject> and select Implement Interface => Implement Interface, Visual Studio helpfully adds the following block of code:

IEnumerator<MyObject> IEnumerable<MyObject>.GetEnumerator()
{
    throw new NotImplementedException();
}

Returning the non generic IEnumerable object from the GetEnumerator(); method doesn't work this time, so what do I put here? The CLI now ignores the non generic implementation and heads straight for the generic version when it tries to enumerate through my array during the foreach loop.

7 Answers 7

194

If you choose to use a generic collection, such as List<MyObject> instead of ArrayList, you'll find that the List<MyObject> will provide both generic and non-generic enumerators that you can use.

using System.Collections;

class MyObjects : IEnumerable<MyObject>
{
    List<MyObject> mylist = new List<MyObject>();

    public MyObject this[int index]  
    {  
        get { return mylist[index]; }  
        set { mylist.Insert(index, value); }  
    } 

    public IEnumerator<MyObject> GetEnumerator()
    {
        return mylist.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}
5
  • 1
    In the non-generic implementation, is there a difference between returning this.GetEnumerator() and simply returning GetEnumerator()? Commented Mar 20, 2015 at 20:14
  • 2
    @TannerSwett There is no difference. Commented Mar 25, 2015 at 18:35
  • You might as well inherit from Collection<MyObject> and then you won't have to write any custom code. Commented Oct 2, 2018 at 21:23
  • @ja72 What if you're already inheriting from another base class and cannot inherit from Collection<MyObject>? Commented Oct 9, 2018 at 22:41
  • 1
    @MonroeThomas - then you have to wrap List<T> and implement IEnumerable<T> as shown in your answer. Commented Oct 9, 2018 at 22:55
92

You probably do not want an explicit implementation of IEnumerable<T> (which is what you've shown).

The usual pattern is to use IEnumerable<T>'s GetEnumerator in the explicit implementation of IEnumerable:

class FooCollection : IEnumerable<Foo>, IEnumerable
{
    SomeCollection<Foo> foos;

    // Explicit for IEnumerable because weakly typed collections are Bad
    System.Collections.IEnumerator IEnumerable.GetEnumerator()
    {
        // uses the strongly typed IEnumerable<T> implementation
        return this.GetEnumerator();
    }

    // Normal implementation for IEnumerable<T>
    IEnumerator<Foo> GetEnumerator()
    {
        foreach (Foo foo in this.foos)
        {
            yield return foo;
            //nb: if SomeCollection is not strongly-typed use a cast:
            // yield return (Foo)foo;
            // Or better yet, switch to an internal collection which is
            // strongly-typed. Such as List<T> or T[], your choice.
        }

        // or, as pointed out: return this.foos.GetEnumerator();
    }
}
5
  • 3
    This is a good solution if SomeCollection<T> does not already implement IEnumerable<T>, or if you need to transform or do other processing on each element before it is returned in the enumeration sequence. If neither of these conditions are true, then it is probably more efficient to just return this.foos.GetEnumerator(); Commented Jul 2, 2012 at 15:55
  • @MonroeThomas: agreed. No clue what collection the OP is using.
    – user7116
    Commented Jul 2, 2012 at 15:58
  • 11
    Good point. But implementing IEnumerable is redundant (IEnumerable<T> already inherits from it).
    – rsenna
    Commented Dec 18, 2014 at 17:21
  • @rsenna that's true, however keep in mind even .NET interfaces like IList redundantly implement interfaces, it's for readability - public interface IList : ICollection, IEnumerable Commented Dec 11, 2018 at 9:31
  • @Backwards_Dave I actually (still) think it makes less readable, since it adds unnecessary noise, but I understand what you said, and think it's a valid opinion.
    – rsenna
    Commented Dec 11, 2018 at 11:03
26

Why do you do it manually? yield return automates the entire process of handling iterators. (I also wrote about it on my blog, including a look at the compiler generated code).

If you really want to do it yourself, you have to return a generic enumerator too. You won't be able to use an ArrayList any more since that's non-generic. Change it to a List<MyObject> instead. That of course assumes that you only have objects of type MyObject (or derived types) in your collection.

3
  • 2
    +1, it should be noted that the preferred pattern is to implement the generic interface and explicitly implement the non-generic interface. Yield return is the most natural solution to the generic interface.
    – user7116
    Commented Jul 2, 2012 at 15:45
  • 7
    Unless the OP is going to be doing some processing in the enumerator, using yield return just adds the overhead of another state machine. The OP should just return an enumerator provided by an underlying generic collection. Commented Jul 2, 2012 at 15:51
  • 1
    @MonroeThomas: You're right. I didn't read the question very carefully before writing about yield return. I wrongly assumed that there were some custom processing. Commented Jul 2, 2012 at 15:55
5

If you work with generics, use List instead of ArrayList. The List has exactly the GetEnumerator method you need.

List<MyObject> myList = new List<MyObject>();
0

make mylist into a List<MyObject>, is one option

0

Note that the IEnumerable<T> allready implemented by the System.Collections so another approach is to derive your MyObjects class from System.Collections as a base class (documentation):

System.Collections: Provides the base class for a generic collection.

We can later make our own implemenation to override the virtual System.Collections methods to provide custom behavior (only for ClearItems, InsertItem, RemoveItem, and SetItem along with Equals, GetHashCode, and ToString from Object). Unlike the List<T> which is not designed to be easily extensible.

Example:

public class FooCollection : System.Collections<Foo>
{
    //...
    protected override void InsertItem(int index, Foo newItem)
    {
        base.InsertItem(index, newItem);     
        Console.Write("An item was successfully inserted to MyCollection!");
    }
}

public static void Main()
{
    FooCollection fooCollection = new FooCollection();
    fooCollection.Add(new Foo()); //OUTPUT: An item was successfully inserted to FooCollection!
}

Please note that driving from collection recommended only in case when custom collection behavior is needed, which is rarely happens. see usage.

0
0

.... and do not forget the using if you are blocked by

    IEnumerator IEnumerable.GetEnumerator()
    {
        // uses the strongly typed IEnumerable<T> implementation
        return GetEnumerator();
    }

add this:

using System.Collections;

also:

: IEnumerable<string>

is sufficient has it is embedding the IEnumerable:

public interface IEnumerable<out T> : IEnumerable

... also beware of Syntax jokes between the A in enumrAble and the o in enumratOr which are both used in this pattern ! Nice dangerous line:

IEnumerator IEnumerable.GetEnumerator()

Not the answer you're looking for? Browse other questions tagged or ask your own question.