tags:

views:

119

answers:

7

I noticed that IEnumerable (Generics) requires 2 methods to be implemented:

1. IEnumerator<T> GetEnumerator()

2. IEnumerable.GetEnumerator() Method

(http://msdn.microsoft.com/en-us/library/19e6zeyy.aspx)

What is #2 and how I am supposed to define/implement this?

From my playing around with some code, it seems like the IEnumerator GetEnumerator() is called in the foreach loop. Where does #2 IEnumerable.GetEnumerator come into play?

I was going through recipe 6.1 Creating an Iterator on a Generic Type in Oreilly's C# 3.0 Cookbook and I was getting an error because #2 was not implemented (It wasn't included in the recipe code).

Thank you!

+1  A: 

#2 is the Explicit non-generic implementation of the GetEnumerator method from the IEnumerable interface. #1 in your example is the implementation of GetEnumerator() for the IEnumerable<T> interface.

IEnumerable.GetEnumerator() can call the same underlying code as IEnumerable, it's just not as strongly typed (returns object instead of a strongly typed IEnumerator).

Justin Niessner
+9  A: 

The first is the generic GetEnumerator, while the second is the non-generic. They do functionally the same work, but the non-generic can only return an object type.

The easiest way to implement these is to implement the generic version, then provide this for the non-generic:

IEnumerator IEnumerable.GetEnumerator() {
   return GetEnumerator();
}
spoulson
A: 

To implement the second interface, do an explicit implementation that simply calls the implicit implementation of the generic interface. Something like

class FooCollection : IEnumerable<Foo>, IEnumerable
{
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public IEnumerator<Foo> GetEnumerator()
    {
        // return enumerator
    }
}

Edit: Inheriting from IEnumerable is redundant, but this answer demonstrates that both interfaces are to be implemented when you inherit IEnumerable<T>, since IEnumerable<T> derives from IEnumerable.

Anthony Pegram
-1 : IEnumerable<Foo> implements IEnumerable already.
x0n
@x0n, that's partially a good point, my code is redundant in the interface inheritance declaration part, but it does show what is going on. Implementing the generic interface requires implementing the non-generic interface. To be accurate, though, `IEnumerable<T>` does not *implement* `IEnumerable`. It can't.
Anthony Pegram
I didn't mean to dock you a point in retrospect - a simple comment would have sufficed. I'll reverse it. update: I can't reverse the score unless you edit your question to fix the redundancy ;-)
x0n
and yes, "implement" is the wrong verb. "derives from" or "inherits" is what I meant. Doh.
x0n
+1  A: 

You only need to define the generic one (which returns String in my example) and then tell the non-generic GetEnumerator method to call the generic GetEnumerator (which returns Object.)

class Foo : IEnumerable<string>
{
    public IEnumerator<string> GetEnumerator()
    {
        foreach (string value in new[] { "a", "b", "c" })
        {
            yield return value;
        }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}
x0n
+2  A: 

Non-generic IEnumerable interface is used for back-compatibility, also it provides very useful to access generic IEnumerable interface in non-generic manner.

You can implement only IEnumerable.GetEnumerator member, and just explicity implement other interface like

IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); /*generic method call*/ }
STO
+1  A: 

The second is for code written for .NET v1.1, which don't understand generics.

Generally, you just have it return the value from the generic GetEnumerator()

IEnumerator IEnumerable.GetEnumerator()
{
     return GetEnumerator();
}
James Curran
A: 

Generally you shouldn't need to implement IEnumerable yourself anymore. there are numerous built-in classes in the framework that implement this interface is various different ways to satisfy 99% of your needs.

However, if you want to, the IEnumerable,GetEnumerator() method is the one that will return an IEnumerator object to a client calling foreach This Ienumerator object is the object that keeps track of which element in the collection is the "next" one one to be returned when the foreach "iterates". For this to work, you have to define a class which will be that Enumerator (It must implement IEnumerator, or generically IEnumerator)

As an example (for a PersonCollection)

public IEnumerator GetEnumerator() { return new myTypeEnumerator(this); }
public class myTypeEnumerator : IEnumerator
{
    int nIndex;
    PersonCollection pers;
    public myTypeEnumerator(PersonCollection myTypes) 
     { pers = myTypes; nIndex = -1; }
    public bool MoveNext() { return (++nIndex < pers.alPers.Count); }
    public object Current { get { return (pers[nIndex]); } }
    public void Reset() { nIndex = -1; }
}

The only difference between this and the generic version is that the generic version is strongly typed:

public IEnumerator<T> GetEnumerator() { return new myTypeEnumerator<T>(this); }
public class myTypeEnumerator<T> : IEnumerator<T>
{
    int nIndex;
    IList<T> tList;
    public myTypeEnumerator(IList<T> listOfTs) 
     { 
        tList = listOfTs; 
        nIndex = -1; 
     }
    public bool MoveNext() { return (++nIndex < tList.Count); }
    public T Current { get { return (tList[nIndex]); } }
    public void Reset() { nIndex = -1; }
}
Charles Bretana