tags:

views:

386

answers:

4

Why do you think Microsoft wants us to go through IEnumerable to get to IEnumerator? Isn't the presence or absence of a valid cast to IEnumerator for a given type enough to determine if the type is enumerable or not?

For example whats wrong with the following?

class MyClass : IEnumerator
{
 ...
}

MyClass myObj = new MyClass();

if(myObj as IEnumerator != null)
{
 Console.WriteLine("myObj is enumerable");
}
else
{
 Console.WriteLine("myObj doesn't support enumeration");
}
+10  A: 

You might have two threads enumerating - each needs its own enumerator.

IEnumerable.GetEnumerator returns an enumerator that is initially positioned before the first element of the collection. If you only had IEnumerator, you'd have to remember to reset yourself before using it, even in a single-threaded scenario.

Joe
Ok, this seems like a valid justification but is this the best/only solution to the problem of multiple concurrent enumeration clients?
SDX2000
This a benefit of doing this but the main concern is seperating state and data. As mentioned not only in my response but also devio's
Harald Scheirich
Please see my comment to your post. State and data cannot always be separated even if you want it badly. Besides state and data here are the same thing. Data is the state for another object.
SDX2000
+5  A: 

An IEnumerator holds state information necessary to perform enumeration, such as array index etc.

The enumeration state information is NOT part of the enumerable object, therefore casting would not be powerful enough.

Also, the enumerator/enumerable separation allows several enumerations to be performed simultaneously on the same enumerable collection.

devio
+1  A: 

It is a matter of seperating responsibilities, IEnumerable is a class that can be iterated over IEnumerator is a class that does the iteration.

Harald Scheirich
I fail to see how responsibilities can actually be separated. Can a class without access to the internal details of another class really enumerate its elements without any help from the enumerable class?
SDX2000
An elegeant(?) way of doing this would be to use inner classes (types) but this isn't exactly what I would call separation.
SDX2000
The implementation might not be seperable but the interface can be, look at STL iterators, while there is an iterator for each container the iterator _interface_ is independent of the implementation. In your example a class could return an enumerator without having to _be_ a enumerator
Harald Scheirich
SDX: Consider how you'd implement an IEnumerator for a List<T>. Given that you know the size and can get an item by index, it's easy! Detecting changes would be the tricky bit, but apart from that it's simple.
Jon Skeet
@Jon: IMHO The fact that a List<T> can be accessed by an index makes it enumerable even if does not implement IEnumerable. This is what I meant when I said "without any help from the enumerable class". The class being enumerated always ends up being the enumerator in some way.
SDX2000
Well yes, if you can't get access to the data then you clearly can't implement IEnumerable over it. I would hope that could be taken as read. The main thing in my view isn't actually a separate of concerns so much as a separation of *state*. An IEnumerator has state which the collection doesn't.
Jon Skeet
(Sorry, I mean as in it's got "extra" state - namely the position within the enumeration.)
Jon Skeet
Yes, I agree with you on separation of "state", since this is how the issue of "multiple concurrent enumeration clients" is taken care of.
SDX2000
+1  A: 

The accepted answer talks about multi-threading, but single-threaded algorithms would be severely limited as well. Remembering to reset the list to the start wouldn't be a problem with foreach to help you, but suppose you wanted to compare every item on the list with every other item:

int matchCount = 0;

foreach (var x in myList)
{
    foreach (var y in myList)
    {
        if (x == y)
            matchCount++;
    }
}

matchCount /= 2;

If the "current position" was stored inside the list object, both inner and outer loops would be fighting over the same location to store their current position. Presumably the inner loop would run once, and then the outer loop would exit, having found itself to be past the end of the list.

Daniel Earwicker