Implementing IEnumerable easily

Say that you’re implementing a linked list, and you want an enumerator:

public IEnumerator<T> GetEnumerator()
{
    return new Stream<T,Node>(first,
        node => node.next == null ? null : Tuple.Of(node.next, node.datum).AsNullable());
}

This uses the following utility class to implement the enumerator in one line (along with some code for Tuples and an extension method for structs):

public class Stream<Tdata, Tstate> : IEnumerator<Tdata>
{
    private Tdata current;
    private Tstate initialState;
    private Tstate state;
    private Func<Tstate, Pair<Tstate, Tdata>?> moveNext;
 
    public Stream(Tstate initialState, Func<Tstate, Pair<Tstate, Tdata>?> calcNextValue)
    {
        moveNext = calcNextValue;
        this.initialState = initialState;
        Reset();
    }
 
    #region IEnumerator<Tdata> Members
 
    public Tdata Current
    {
        get { return current; }
    }
 
    #endregion
 
    #region IDisposable Members
 
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
 
    protected void Dispose(bool disposing)
    {
        if (disposing)
        {
            var disposeCurrent = current as IDisposable;
            if (disposeCurrent != null)
                disposeCurrent.Dispose();
 
            var disposeState = state as IDisposable;
            if (disposeState != null)
            {
                disposeState.Dispose();
                //safe; have checked already above.
                //type of state == type of initialstate
                ((IDisposable)initialState).Dispose();
            }
        }
    }
 
    #endregion
 
    #region IEnumerator Members
 
    object System.Collections.IEnumerator.Current
    {
        get { return current; }
    }
 
    public bool MoveNext()
    {
        var result = moveNext(state);
 
        if (result.HasValue)
        {
            current = result.Value.Right;
            state = result.Value.Left;
            return true;
        }
        else
            return false;
    }
 
    public void Reset()
    {
        state = initialState;
    }
 
    #endregion
}

Post a Comment

Your email is never published nor shared. Required fields are marked *