In the framework classes of collections I have often seen IEnumerator<T>
separately implemented as an inner class and an instance of it is returned in the GetEnumerator
method.
Now suppose I'm writing my own collection classes which will have an inbuilt collection like List<T>
or T[]
act as the holder internally, say like this:
public class SpecialCollection<T> : IEnumerable<T>
{
List<T> list;
public SpecialCollection<T>()
{
}
public IEnumerator<T> GetEnumerator()
{
return list.GetEnumerator();
//or
return list.Where(x => some logic).GetEnumerator();
//or directly rely on yield keyword
yield return x; //etc
}
}
Should I be writing my own enumerator class, or is it ok to return enumerator of the List<T>
class? Is there any circumstance under which should I be writing my own enumerator class?
I have a related question as well. If it's not all that important or doesn't make much of a difference, why do every collection class in the BCL write their own IEnumerator
?
For eg, List<T>
class has something like
T[] items;
public IEnumerator<T> GetEnumerator()
{
return new List<T>.Enumerator(items);
}
array.Select(x => x).GetEnumerator();
, you can use((IEnumerable<T>)array).GetEnumerator()
. One-dimensional arrays implement the generic interfaces in a "magical" way that looks like explicit interface implementation from the outside. – Brood// some logic
was meant that some additional logic can be added to the enumerator. – Stoddardclass MyColl : IEnumerable<int>
. I could hold my values in an array internally, so have a fieldprivate int[] array;
. Now, when I need to implement the generic interface, I can't just sayreturn array.GetEnumerator();
(compile-time error) because of the not-quite-generic nature of arrays (hereint[]
). I could solve that byreturn array.Select(x => x).GetEnumerator();
. But that is wasteful. Instead usereturn ((IEnumerable<int>)array).GetEnumerator();
or equivalentlyreturn array.AsEnumerable().GetEnumerator();
. See what I mean? – Broodforeach
and why struct is preferred over a reference type. It doesn't talk anything about re-using the existing enumerator implementations. – HeymanList<T>
has its own (struct) enumerator type. – BracteateGetEnumerator
of the backing array (which is what my question is about). It talks about why it is required to be struct in the first place. My q is, if you require a struct, then why not re-use the already implemented struct of backing array. I hope its clear. Not to be nitpicking, but honestly the link doesnt clear my confusion at all. Eric's answer does. – Heymanforeach
over an array is recognized by the compiler and transformed into afor
loop instead, as that's much faster. This means that only boxed array enumerators are actually used, and the act of boxing also eliminates the possibility of the list-style optimizations as well, so there's no need for arrays to use the list's trick of having a struct as an enumerator (so they don't; their enumerator is aclass
), because they have something even better that's specific to them. – RotundIEnumerator<T>
of the array, you wouldn't be able to detect the list changing between calls, which should trigger an exception. – BracteateList<T>
,Queue<T>
) in the framework is not a bad choice considering they do catch modifications. – Heyman