I am writing a library function to split an enumeration into multiple spans of enumerations but am running into an inexplicable issue with the enumerator from linq Select clause. Please see representative code sample and output below.
This smells like a struct enumerator problem but I cannot for the life of me pinpoint the issue so as to work around it.
Help is much appreciated!
class Program
{
private static IEnumerable<IEnumerable<T>> wrap<T>(IEnumerable<T> collection)
{
return wrapped();
IEnumerable<IEnumerable<T>> wrapped()
{
Console.Write($"{collection.Count()} items: ");
using (var etor = collection.GetEnumerator())
{
if (!(etor is object)) throw new Exception();
yield return inner();
IEnumerable<T> inner() { while (etor.MoveNext()) yield return etor.Current; }
}
}
}
static void Main(string[] args)
{
var c1 = Enumerable.Range(0, 5);
var c2 = Enumerable.Range(0, 5).Select(x => x);
var c3 = Enumerable.Range(0, 5).Select(x => x).ToList();
print(wrap(c1).First()); // ok
print(wrap(c2).First()); // empty!
print(wrap(c3).First()); // ok
Console.WriteLine("<done>"); Console.ReadKey();
void print<T>(IEnumerable<T> tt) => Console.Write(string.Join(", ", tt) + "\n");
}
}
Console output:
5 items: 0, 1, 2, 3, 4
5 items:
5 items: 0, 1, 2, 3, 4
<done>
The problem is caused by the using
statement:
IEnumerable<IEnumerable<T>> wrapped()
{
using (var etor = collection.GetEnumerator())
{
yield return inner();
IEnumerable<T> inner()
{
while (etor.MoveNext()) yield return etor.Current;
}
}
}
The enumerator is disposed immediately after yielding the inner()
enumerable, so the inner iterator tries to enumerate a disposed enumerator. Not all enumerators behave the same when disposed. Apparently the enumerator of the List<T>
is not affected by the disposal, while the enumerator of the Select
does.