Is there a built-in way to convert IEnumerator
to IEnumerable
?
This is a variant I have written... The specific is a little different. I wanted to do a MoveNext()
on an IEnumerable
, check the result, and then roll everything in a new IEnumerator
that was "complete" (so that included even the element of the IEnumerable
I had already extracted)
// Simple IEnumerable that "uses" an IEnumerator that has
// already received a MoveNext(). "eats" the first MoveNext()
// received, then continues normally. For shortness, both IEnumerable
// and IEnumerator are implemented by the same class. Note that if a
// second call to GetEnumerator() is done, the "real" IEnumerator will
// be returned, not this proxy implementation.
public class EnumerableFromStartedEnumerator : IEnumerable, IEnumerator
{
public readonly IEnumerator Enumerator;
public readonly IEnumerable Enumerable;
// Received by creator. Return value of MoveNext() done by caller
protected bool FirstMoveNextSuccessful { get; set; }
// The Enumerator can be "used" only once, then a new enumerator
// can be requested by Enumerable.GetEnumerator()
// (default = false)
protected bool Used { get; set; }
// The first MoveNext() has been already done (default = false)
protected bool DoneMoveNext { get; set; }
public EnumerableFromStartedEnumerator(IEnumerator enumerator, bool firstMoveNextSuccessful, IEnumerable enumerable)
{
Enumerator = enumerator;
FirstMoveNextSuccessful = firstMoveNextSuccessful;
Enumerable = enumerable;
}
public IEnumerator GetEnumerator()
{
if (Used)
{
return Enumerable.GetEnumerator();
}
Used = true;
return this;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public T Current
{
get
{
// There are various school of though on what should
// happens if called before the first MoveNext() or
// after a MoveNext() returns false. We follow the
// "return default(TInner)" school of thought for the
// before first MoveNext() and the "whatever the
// Enumerator wants" for the after a MoveNext() returns
// false
if (!DoneMoveNext)
{
return default(T);
}
return Enumerator.Current;
}
}
public void Dispose()
{
Enumerator.Dispose();
}
object IEnumerator.Current
{
get
{
return Current;
}
}
public bool MoveNext()
{
if (!DoneMoveNext)
{
DoneMoveNext = true;
return FirstMoveNextSuccessful;
}
return Enumerator.MoveNext();
}
public void Reset()
{
// This will 99% throw :-) Not our problem.
Enumerator.Reset();
// So it is improbable we will arrive here
DoneMoveNext = true;
}
}
Use:
var enumerable = someCollection;
var enumerator = enumerable.GetEnumerator();
bool res = enumerator.MoveNext();
// do whatever you want with res/enumerator.Current
var enumerable2 = new EnumerableFromStartedEnumerator(enumerator, res, enumerable);
Now, the first GetEnumerator()
that will be requested to enumerable2
will be given through the enumerator enumerator
. From the second onward the enumerable.GetEnumerator()
will be used.