Enumerators in C#
Tigraine
Daniel Hoelbling talks about programming and technology

Enumerators in C#

January 12, 2008 by Daniel Hoelbling

I am still trying to figure out if what I did was useful or not.

Based on the assumption that sometimes you may need a variable typed IEnumerable<T> to hold a value that only implements IEnumerable I wrote this adapter class (you find it after the jump).

What's IEnumerator?
IEnumerator it the old non-generic implementation of the Iterator pattern, while IEnumerator<T> is the strongly-typed generic version introduced in .NET 2.0.

IEnumerable<T> implements IEnumerable, but there is no way to cast IEnumerable to IEnumerable<T>. So I wondered how you could comply to the Iterator pattern.

My first suspicion came when I tried foreach on both IEnumerables. Foreach has no problem with both of them, so I dug out my C# language spec and discovered that foreach has to use two different methods for either IEnumerable or IEnumerable<T> (That's not really clear there, anyone to falsify my assumption?).
They could have gone the other way and use the non-generic IEnumerable for the iteration, but that would need an implicit typecast on every iteration (and that would slow things down I guess).

In a scenario like the following one you can't pass the Enumerator created by an Array.GetEnumerator() because it uses IEnumerator instead of the generic version IEnumerator<T>.

public void PrintList(IEnumerable<String> MyList)
{
  
foreach (String Entryin MyList)
    {
      
Console.WriteLine("{0}", Entry);
    }
}

Because IEnumerable<T> implements IEnumerable you could just switch back to the non-generic version, but that's something I don't really like (although it may be more practical).

So here are 2 (very simple) adapter classes that will provide upward-compatibility to your IEnumerable and IEnumerator needs:


public class GenericEnumerableAdapter<T> : IEnumerable<T>
{
    private IEnumerable _Old;
    
    public GenericEnumerableAdapter(IEnumerable OldEnumerable)
    {
        this._Old = OldEnumerable;
    }

    #region IEnumerable<T> Members

    public IEnumerator<T> GetEnumerator()
    {
        return new GenericEnumeratorAdapter<T>(_Old.GetEnumerator());
    }

    #endregion

    #region IEnumerable Members

    IEnumerator IEnumerable.GetEnumerator()
    {
        return _Old.GetEnumerator();
    }

    #endregion
}

public class GenericEnumeratorAdapter<T> : IEnumerator<T>
{
    private IEnumerator _OldEnum;
    public GenericEnumeratorAdapter(IEnumerator OldEnumerator)
    {
        _OldEnum = OldEnumerator;
    }

    #region IDisposable Members

    public void Dispose()
    {
        this._OldEnum = null;
    }

    #endregion

    #region IEnumerator<T> Members

    public T Current
    {
        get { return (T)_OldEnum.Current; }
    }

    object IEnumerator.Current
    {
        get { return _OldEnum.Current; }
    }

    public bool MoveNext()
    {
        return _OldEnum.MoveNext();
    }

    public void Reset()
    {
        _OldEnum.Reset();
    }

    #endregion
}