开发者

Why was GetEnumerator() stored in a separate interface from IEnumerator?

I was wondering why the GetEnumerator() method was factored out of IEnumerator and placed in IEnumerable. It seems to me that it would make more sense to ke开发者_JAVA百科ep all of the enumerator methods in IEnumerator.

Thanks,

Scott


Ask yourself "imagine if this were true".

If all the enumeration methods were on a single interface, how could two callers enumerate the same list at the same time?

There are two interfaces because one says, "You can enumerate me," while the other says, "here's an object that keeps track of a given enumeration task."

The IEnumerable interface is a factory that creates as many IEnumerator objects as you want. How and when those enumerators get used is up to the consumer.


IEnumerable implies that the object is a collection or source of data which can be iterated over in a linear fashion. IEnumerator is the interface for the actual implementation which performs the iteration.


Because "IEnumerable" says "come, enumerate me" (and then you say- how, give me the Enumerator), however "IEnumerator" says "I can enumerate your collection!" and you already have it, you don't need to get any more.


You got very good answers here. Just some emphasis. An enumerator keeps state, it keeps track of the current object in the collection being enumerated. Available through IEnumerator.Current. And it knows how to change that state, IEnumerator.MoveNext(). Keeping state requires a separate object that stores the state. That state can't be stored inside the collection object easily because there's only one collection object but there can be more than one enumerator.

I used the phrase "easily" because it is actually possible for a collection to keep track of its enumerators. After all, it was a call to the collection class' GetEnumerator() method that returned the iterator. There's one collection class in the .NET framework that does this, Microsoft.VisualBasic.Collection. It needed to implement a VB6 contract for its Collection class and that contract specifies that changing a collection while it is being enumerated is legal. Which means that when the Collection is modified, it needs to some reasonable with all of the iterator objects that were created.

They came up with a pretty good trick, WeakReference might have been inspired by this. Have a look-see at the code shown by Reflector. Inspiring stuff. Dig some more and find "version" in the collection classes. Awesome trick.


Because often the thing doing the enumerating is only tangentially (if at all) related to the thing being enumerated. If IEnumerable and IEnumerator were the same interface, they couldn't be shared, or you'd need to have some untyped argument on GetEnumerator that allowed you to pass in the object to be enumerated. Splitting them allows the enumeration infrastructure to be potentially shared across different types.


After reading Bart De Smet's post on minlinq I'm no longer convienced that splitting the two interfaces is strictly required.

For instance - In the above link, IEnumerable/IEnumerator is collaped to a single method Interface

Func<Func<Option<T>>>

and some basic implementations

public static class FEnumerable
{
    public static Func<Func<Option<T>>> Empty<T>()
    {
        return () => () => new Option<T>.None();
    }

    public static Func<Func<Option<T>>> Return<T>(T value)
    {
        return () =>
        {
            int i = 0;
            return () =>
                i++ == 0
                ? (Option<T>)new Option<T>.Some(value)
                : (Option<T>)new Option<T>.None();
        };
    }

    ...

}

public static Func<Func<Option<T>>> Where<T>(this Func<Func<Option<T>>> source, Func<T, bool> filter)
{
    return source.Bind(t => filter(t) ? FEnumerable.Return(t) : FEnumerable.Empty<T>());
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜