If you just want to create a wrapper for IEnumerable that will handle any LINQ added and passing one pass through the source, use this class and extension:
public static class EnumerableOnceExt { public static EnumerableOnce<IEnumerable<T>, T> EnumerableOnce<T>(this IEnumerable<T> src) => new EnumerableOnce<IEnumerable<T>, T>(src); } public class EnumerableOnce<T, V> : IEnumerable<V>, IDisposable where T : IEnumerable<V> { EnumeratorOnce<V> onceEnum; public EnumerableOnce(T src) { onceEnum = new EnumeratorOnce<V>(src.GetEnumerator()); } public IEnumerator<V> GetEnumerator() { return onceEnum; } IEnumerator IEnumerable.GetEnumerator() { return onceEnum; } public void DoSkip(int n) { while (n > 0 && onceEnum.MoveNext()) --n; } public void DoTake(int n) { while (n > 0 && onceEnum.MoveNext()) --n; } #region IDisposable Support private bool disposedValue = false;
Now your sample code will work if you call EnumerableOnce() to wrap the source code while you are doing the enumerations:
var it1 = it.EnumerableOnce(); it1.Take(10).ToList(); var @continue = it1.Select(Mutate); @continue.Take(20).ToList(); @continue = @continue.Where(Filter); @continue.Take(5).ToList();
You can also add new methods to EnumerableOnce :
public void DoSkip(int n) { while (n > 0 && srcEnum.MoveNext()) --n; } public void DoTake(int n) { while (n > 0 && srcEnum.MoveNext()) --n; }
And call them:
var it1 = it.EnumerableOnce(); it1.DoTake(10); var @continue = it1.Select(Mutate); @continue.DoSkip(20); @continue = @continue.Where(Filter); @continue.DoTake(5);
Netmage
source share