Consider this example:
List<int> l = [1, 2, 3, 4, 5];
void DoSomethingWith(IEnumerator<int> e) {
Console.WriteLine(e.MoveNext());
Console.WriteLine(e.Current);
}
using(var e = l.GetEnumerator()) {
DoSomethingWith(e);
DoSomethingWith(e);
}
This snippet outputs:
True
1
True
1
I expect
True
1
True
2
because I pass in the same enumerator.
Why is this the case?
List<T>.Enumerator
returned by List<T>.GetEnumerator
is a struct
so passing it by interface will box it (so subsequent invocations will work with different instances copied from the current state). For example the following:
using(var e = l.GetEnumerator())
{
e.MoveNext();
DoSomethingWith(e);
DoSomethingWith(e);
}
Will print:
True
2
True
2
So as you can see the original enumerator is not actually reset.
You can either specify the type explicitly in the using
as interface (so you will box one time and pass the same instance of the enumerator):
using(IEnumerator<int> e = l.GetEnumerator())
{
e.MoveNext();
DoSomethingWith(e);
DoSomethingWith(e);
}
Or change the method to accept List<int>.Enumerator
and pass it by ref
:
void DoSomethingWith(ref List<int>.Enumerator e)
{
Console.WriteLine(e.MoveNext());
Console.WriteLine(e.Current);
}
var e = l.GetEnumerator();
DoSomethingWith(ref e);
DoSomethingWith(ref e);
Or work with collection via interface, since IEnumerable<T>.GetEnumerator()
is implemented explicitly and the boxing will be handled by the implementation:
IEnumerable<int> lAsEn = l;
using(var e = lAsEn.GetEnumerator()) {
DoSomethingWith(e);
DoSomethingWith(e);
}