tags:

views:

50

answers:

3

let's have this code :

class MyList : IEnumerable, IEnumerator
{
    int[] A = { 1, 2, 3, 4, 5 };
    int i = -1;

    #region IEnumerator Members

    public object Current
    {
        get { return A[i]; }
    }

    public bool MoveNext()
    {
        i++;
        return i < 5;
    }

    public void Reset()
    {
        i = -1;
    }

    #endregion

    #region IEnumerable Members

    public IEnumerator GetEnumerator()
    {
        return (IEnumerator)this;
    }

    #endregion
}

And In Main Method :

MyList list = new MyList();
foreach (int i in list)
{
    Console.WriteLine(i);
}

foreach (int i in list)
{
    Console.WriteLine(i);
}

Why the second foerach doesn't work ?? and the "i" doesn't initialize again ??

Is that true : Reset method should be called automatically before foreach is executed ??

why it doesn't call here ??

+2  A: 

Reset is not called by foreach. Looking at your Main method in Reflector confirms this.

The .NET classes, like ArrayList, actually return a new instance of a class that implements IEnumerator.

For example ArrayList implements IEnumerable, and its GetEnumerator method looks like this:

public virtual IEnumerator GetEnumerator()
{
    return new ArrayListEnumeratorSimple(this);
}

so there is no need to worry about calling Reset since every foreach uses a new instance of the enumerator.

For a complete example showing the implementation of IEnumerable and a separate class implementing IEnumerator, you can look at the documentation for IEnumerable.

adrift
+1  A: 

The iEnumerable and iEnumerator should generally be separate classes, and except in the case of enumerators that always return empty or always return the same item, the GetEnumerator method must always return a new instance of an iEnumerator. There isn't much point to iEnumerator.Reset; for-each loops don't use it, and consumers of an iEnumerable/iEnumerator can't use it unless they know what the enumerable type is, in which case they could use the actual type rather than the interface.

supercat
+2  A: 

Reset is redundant; so much so that it is a requirement in the language spec for iterator blocks to throw an exception on Reset. The correct thing to do is simply dispose and release the old iterator, and call GetEnumerator again. Or better: avoid having to read it twice, since not all data is repeatable.

Marc Gravell