My class that implements IEnumerator and IEnumerable doesn't go to foreach statement

I have a class that stores a string list, I would like to make this class usable in a foreach statement, so I found these two interfaces and I tried to implement them.

public class GroupCollection : IEnumerable, IEnumerator
{
    public List<string> Groups { get; set; }
    public int Count { get { return Groups.Count; } }
    int position = -1;
}

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

public object Current
{
    get
    {
        try
        {
            return new Group(Groups[position]);
        }
        catch (IndexOutOfRangeException)
        {
            throw new InvalidOperationException();
        }
    }
}

public bool MoveNext()
{
    position++;
    return position < Groups.Count;
}

public void Reset()
{
    position = 0;
}

I'm iterating through a GroupCollection variable twice:

foreach (GroupCollection.Group in groups) // where groups is a GroupCollection
{
}

foreach (GroupCollection.Group in groups)
{
}

// where Group is a nested class in GroupCollection.

When it is at the first foreach it works well (count is 1 at this time). I don't modify anything, and when it goes to the second foreach it doesn't go into the loop. I went through the code line by line in debugging mode and found out that the reset is not called after the first foreach. So should I manually call reset after the foreach? Isn't there a nicer way to do this?

Jon Skeet
people
quotationmark

I don't modify anything

Yes you do - your MoveNext() modifies the state of the class. This is why you shouldn't implement both IEnumerable and IEnumerator in the same class. (The C# compiler does for iterator blocks, but that's a special case.) You should be able to call GetEnumerator() twice and get two entirely independent iterators. For example:

foreach (var x in collection)
{
    foreach (var y in collection)
    {
        Console.WriteLine("{0}, {1}", x, y);
    }
}

... should give you all possible pairs of items in a collection. But that only works when the iterators are independent.

I went through the code line by line in debugging mode and found out that the reset is not called after the first foreach.

Why would you expect it to? I don't believe the specification says anything about foreach calling Reset - and that's a good job, as many implementations don't really implement it (they throw an exception instead).

Basically, you should make your GetEnumerator() method return a new object which keeps the mutable state of the "cursor" over your data. Note that the simplest way of implementing an iterator in C# is usually to use an iterator block (yield return etc).

I'd also strongly encourage you to implement the generic interfaces rather than just the non-generic ones; that way your type can be used much more easily in LINQ code, the iterator variable in a foreach statement can be implicitly typed appropriately, etc.

people

See more on this question at Stackoverflow