tags:

views:

97

answers:

2

Apart from (IEnumerable Returns GetEnumerator() ,for "foreach" IEnumerble is essential)

almost the following two approaches allow us to iterate over the collection.What is

the advantage of one over another ? (I am not asking the difference between IEnumerable and IEnumerator).

static void Main()
{
    IEnumerator<int> em = MyEnumerator<int>(new int[] { 1, 2, 3, 4 });
    IEnumerator<int> e = Collection<int>
                        (new int[] { 1, 2, 3, 4 }).GetEnumerator();

    while (em.MoveNext())
    {
        Console.WriteLine(em.Current);
    }

    while (e.MoveNext())
    {
        Console.WriteLine(e.Current);
    }
    Console.ReadKey(true);
}

approach 1

 public static IEnumerator<T> MyEnumerator<T>(T[] vals )

 {
     T[] some = vals;

     foreach (var v in some)
     {
       yield return v;
     }
}

approach 2

public static IEnumerable<T> Collection<T>(T[] vals)
     {
         T[] some = vals;

         foreach (var v in some)
         {
             yield return v;
         }
     }
+1  A: 

Correct me if I'm wrong but the only difference is the difference between IEnumerable and IEnumerator and since you specifically said you're not asking the difference, both are a good...

Zenuka
+1  A: 

The main difference is that most API support an imput of IEnumerable<T> but not of IEnumerator<T>.

You also have to remember to call Reset() when using it while the syntax is more evident in IEnumerable<T> (Just call GetEnumerator again). Also see the comment of Eric Lipper about reset being a bad idea; if Reset isn't implemented in your IEnumerator<T> or is buggy it become a one-time-only enumerator (pretty useless in a lot of cases).

Another difference may be that you could have an IEnumerable<T> that could be enumerated from multiple threads at the same time but an IEnumerator<T> store one position in the enumerated data (Imagine a RandomEnumerable or RangeEnumerable).

So the conclusion is that IEnumerable<T> is more versatile, but anyway if you have a function returning an IEnumerator<T> generating the IEnumerable<T> around it is simple.

class EnumeratorWrapper<T> : IEnumerable<T>
{
    Func<IEnumerator<T>> m_generator;
    public EnumeratorWrapper(Func<IEnumerator<T>> generator)
    {
        m_generator = generator;
    }

    public IEnumerator<T> GetEnumerator()
    {
        return m_generator();
    }

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

Just for API consistency using IEnumerable<T> seem the best solution to me.

But the issue with Reset() in IEnumerator<T> make it an unusable solution anyway, so IEnumerable<T> is the way to go.

VirtualBlackFox
Super duper explanations Thanks
udana
NEVER call Reset. Reset was a bad idea and is almost always not implemented. If you need to re-start an enumeration, just create a new enumerator.
Eric Lippert
Ok so this is one big point against passing around IEnumerator instances, without Reset they are absolutely not viable.
VirtualBlackFox
No, you missed the point. As Eric says, Reset is almost never implemented, so IEnumerable or IEnumerator, in this particular regard, makes no difference. Reset is, as Eric says, a bad idea. Dispose of the old enumerable/enumerator, and create a new one if you need to restart from the beginning. This is always supported, except for destructive iterators.
Lasse V. Karlsen
Sorry but i don't understand your point Lasse. When i said that without Reset-) IEnumerator is useless i wasn't implying that Reset() should be used EVER. I was only speaking about Reset() as a way to bypass the fact that you sometimes need to iterate multiple times over a collection and if you only have an IEnumerator the correct way of doing it (Calling GetEnumerator again) isn't available to you.
VirtualBlackFox