Many of you might have come to the point and wished to have a Peek for IEnumerator and IEnumerator. I tried to implement it by cheating a bit and looking up the next element before the actual MoveNext call. So I ended up with some kind of wrapper.First of the extensions to convert default enumerators:public static class PeekableEnumeratorExtension{    public static PeekableEnumerator ToPeekable(this IEnumerator enumerator)    {        return new PeekableEnumerator(enumerator);    }    public static PeekableEnumerator<T> ToPeekable<T>(this IEnumerator<T> enumerator)    {        return new PeekableEnumerator<T>(enumerator);    }}And here is the non-generic PeekableEnumerator:public class PeekableEnumerator : IEnumerator{    protected enum Status { Uninitialized, Starting, Started, Ending, Ended }    protected IEnumerator enumerator;    protected Status status;    protected object current;    protected object peek;    public PeekableEnumerator(IEnumerator enumerator)    {        this.enumerator = enumerator;        status = Status.Uninitialized;        MoveNext();    }    public object Current    {        get        {            if (Status.Starting == status)                throw new InvalidOperationException(Enumeration has not started. Call MoveNext.);            if (Status.Ended == status)                throw new InvalidOperationException(Enumeration already finished.);            return current;        }    }    public object Peek    {        get        {            if (Status.Ending == status || Status.Ended == status)                throw new InvalidOperationException(Enumeration already finished.);            return peek;        }    }    public bool MoveNext()    {        current = peek;        switch (status)        {            case Status.Uninitialized:            case Status.Starting:                if (enumerator.MoveNext())                {                    status++;                    peek = enumerator.Current;                }                else                    status = Status.Ending;                break;            case Status.Started:                if (enumerator.MoveNext())                    peek = enumerator.Current;                else                    status++;                break;            case Status.Ending:                status++;                break;        }        return Status.Ended != status;    }    public void Reset()    {        enumerator.Reset();        status = Status.Uninitialized;        MoveNext();    }}And the very analog PeekableEnumerator:public class PeekableEnumerator<T> : IEnumerator<T>{    protected enum Status { Uninitialized, Starting, Started, Ending, Ended }    protected IEnumerator<T> enumerator;    protected Status status;    protected T current;    protected T peek;    public PeekableEnumerator(IEnumerator<T> enumerator)    {        this.enumerator = enumerator;        status = Status.Uninitialized;        MoveNext();    }    public T Current    {        get        {            if (Status.Starting == status)                throw new InvalidOperationException(Enumeration has not started. Call MoveNext.);            if (Status.Ended == status)                throw new InvalidOperationException(Enumeration already finished.);            return current;        }    }    object System.Collections.IEnumerator.Current { get { return Current; } }    public T Peek    {        get        {            if (Status.Ending == status || Status.Ended == status)                throw new InvalidOperationException(Enumeration already finished.);            return peek;        }    }    public bool MoveNext()    {        current = peek;        switch (status)        {            case Status.Uninitialized:            case Status.Starting:                if (enumerator.MoveNext())                {                    status++;                    peek = enumerator.Current;                }                else                    status = Status.Ending;                break;            case Status.Started:                if (enumerator.MoveNext())                    peek = enumerator.Current;                else                    status++;                break;            case Status.Ending:                status++;                break;        }        return Status.Ended != status;    }    public void Reset()    {        enumerator.Reset();        status = Status.Uninitialized;        MoveNext();    }    public void Dispose()    {        enumerator.Dispose();    }}Before you ask: Why are there 5 statuses? It is derived from the lifetime of Current and Peek:Status        | Current   | Peek      | Comment--------------+-----------+-----------+-----------------------------------Uninitialized | n/a       | n/a       | Internal for constructor and ResetStarting      | Exception | Available | Before first MoveNextStarted       | Available | Available | After first MoveNextEnding        | Available | Exception | wrapped MoveNext returned falseEnded         | Exception | Exception | After enumeration finishedExample usage:var a = new[] { 1, 2, 3 }.GetEnumerator().ToPeekable();a.Current; // InvalidOperationExceptiona.Peek; // 1a.MoveNext(); // truea.Current; // 1a.Peek; // 2a.MoveNext(); // truea.Current; // 2a.Peek; // 3a.MoveNext(); // truea.Current; // 3a.Peek; // InvalidOperationExceptiona.MoveNext(); // falsea.Current; // InvalidOperationExceptiona.Peek; // InvalidOperationExceptionUpdateThanks to svick here is an alternative version using a Queue. It changes the basic usage from IEnumerator to ICollection as input but I can live with that. I need to keep an copy of the original collection for resetting.public class PeekableEnumerator : IEnumerator{    protected ICollection collection;    protected Queue queue;    protected bool current_set;    protected object current;    protected bool peek_set;    protected object peek;    public object Current    {        get        {            if (!current_set)                if (peek_set)                    throw new InvalidOperationException(Enumeration has not started. Call MoveNext.);                else                    throw new InvalidOperationException(Enumeration already finished.);            return current;        }    }    public object Peek    {        get        {            if (!peek_set)                throw new InvalidOperationException(Enumeration already finished.);            return peek;        }    }    public PeekableEnumerator(ICollection collection)    {        this.collection = collection;        Reset();    }    public bool MoveNext()    {        current_set = peek_set;        current = peek;        if (0 == queue.Count)        {            peek_set = false;            return current_set;        }        else        {            peek_set = true;            peek = queue.Dequeue();            return true;        }    }    public void Reset()    {        queue = new Queue(collection);        MoveNext();    }}
Implementing Peek to IEnumerator and IEnumerator
c#
I think your implementation is too complicated, and what nagged me was that you start enumerate in constructor. Here is my implementation which fix that. The state reduced to a boolean telling that the peek value has been fetched from the underlying enumerator or not.public class PeekEnumerator<T> : IEnumerator<T>{    private IEnumerator<T> _enumerator;    private T _peek;    private bool _didPeek;    public PeekEnumerator(IEnumerator<T> enumerator)    {        if (enumerator == null)            throw new ArgumentNullException(enumerator);        _enumerator = enumerator;    }    #region IEnumerator implementation    public bool MoveNext()    {        return _didPeek ? !(_didPeek = false) : _enumerator.MoveNext();    }    public void Reset()    {        _enumerator.Reset();        _didPeek = false;    }    object IEnumerator.Current { get { return this.Current; } }    #endregion    #region IDisposable implementation    public void Dispose()    {        _enumerator.Dispose();    }    #endregion    #region IEnumerator implementation    public T Current    {        get { return _didPeek ? _peek : _enumerator.Current; }    }    #endregion    private void TryFetchPeek() {        if (!_didPeek && (_didPeek = _enumerator.MoveNext()))        {            _peek = _enumerator.Current;        }    }    public T Peek    {        get {             TryFetchPeek();            if (!_didPeek)                throw new InvalidOperationException(Enumeration already finished.);            return _peek;        }    }}My test to make sure it complies to your needed behaviour:var a = new PeekEnumerator<int>(new [] { 1, 2, 3 }.AsEnumerable().GetEnumerator());Console.WriteLine(a.Peek); // 1Console.WriteLine(a.MoveNext()); // trueConsole.WriteLine(a.Current); // 1Console.WriteLine(a.Peek); // 2Console.WriteLine(a.MoveNext()); // trueConsole.WriteLine(a.Current); // 2Console.WriteLine(a.Peek); // 3Console.WriteLine(a.MoveNext()); // trueConsole.WriteLine(a.Current); // 3try {    Console.WriteLine(a.Peek); // InvalidOperationException}catch (Exception e) {    Console.WriteLine(e.GetType());}Console.WriteLine(a.MoveNext()); // falsetry {    Console.WriteLine(a.Current); // InvalidOperationException}catch (Exception e) {    Console.WriteLine(e.GetType());}try {    Console.WriteLine(a.Peek); // InvalidOperationException}catch (Exception e) {    Console.WriteLine(e.GetType());}