Почему был GetEnumerator () сохранен в отдельном интерфейсе от IEnumerator?

Я задавался вопросом, почему GetEnumerator () метод был учтен из IEnumerator и поместил в IEnumerable. Мне кажется, что имело бы больше смысла сохранять все методы перечислителя в IEnumerator.

Спасибо,

Scott

7
задан Scott Davies 2 January 2010 в 22:43
поделиться

6 ответов

Спросите себя "представьте себе, правда ли это"

Если бы все методы перечисления были на одном интерфейсе, как два вызывающих абонента могли бы перечислить один и тот же список одновременно?

Есть два интерфейса, потому что один говорит: "Вы можете перечислить меня", а другой - "вот объект, который отслеживает задание перечисления"

Интерфейс IEnumerable - это фабрика, которая создает столько объектов IEnumerator, сколько вам нужно. Как и когда эти регистраторы используются, зависит от потребителя.

.
18
ответ дан 6 December 2019 в 05:55
поделиться

IEnumerable подразумевает, что объект является сборником или источником данных, которые могут быть итерацированы линейным способом. IEnumerator - это интерфейс фактической реализации, который выполняет итерацию.

.
7
ответ дан 6 December 2019 в 05:55
поделиться

Поскольку "IEnumerable" говорит "приди, перечисли меня" (а потом ты говоришь - как, дай мне Перечислитель), однако "IEnumerator" говорит "Я могу перечислить твою коллекцию!", а у тебя она уже есть, тебе больше не нужно ее получать.

.
4
ответ дан 6 December 2019 в 05:55
поделиться
-

Здесь у вас очень хорошие ответы. Просто небольшой акцент. Перечислитель сохраняет состояние, отслеживает текущий объект в перечисляемой коллекции. Доступно через IEnumerator.Current. И он знает, как изменить это состояние, IEnumerator.MoveNext(). Для сохранения состояния требуется отдельный объект, который хранит это состояние. Это состояние не может быть легко сохранено внутри объекта коллекции, потому что есть только один объект коллекции, но может быть более одного перечислителя.

Я использовал фразу "легко", потому что на самом деле коллекция может отслеживать свои перечислители. В конце концов, это был вызов метода класса коллекции GetEnumerator(), который вернул итератор. Есть один класс коллекции в .NET фреймворке, который делает это, Microsoft.VisualBasic.Collection. Он должен был реализовать контракт VB6 для своего класса Collection, и этот контракт указывает, что изменение коллекции во время ее перечисления является законным. Что означает, что когда Коллекция изменяется, она должна быть разумной со всеми итераторами, которые были созданы.

Они придумали довольно неплохой трюк, WeakReference, возможно, был вдохновлен этим. Взгляните на код, показанный рефлектором. Вдохновляющий материал. Копайте еще и найдите "версию" в классах коллекции. Отличный трюк.

2
ответ дан 6 December 2019 в 05:55
поделиться

После прочтения сообщения Барта Де Смета на minlinq я больше не уверен, что разделение двух интерфейсов строго необходимо.

Например - В приведенной выше ссылке IEnumerable/IEnumerator привязан к одному методу Interface

Func<Func<Option<T>>>

и некоторым базовым реализациям

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
ответ дан 6 December 2019 в 05:55
поделиться

Потому что часто вещь, делающая перечисление, только по касательной (если вообще) связана с перечисляемой вещью. Если бы IEnumerable и IEnumerator были одним и тем же интерфейсом, их нельзя было бы использовать совместно, или вам понадобился бы какой-нибудь непонятный аргумент в GetEnumerator, который позволял бы вам передавать в перечисляемом объекте. Разделение их позволяет потенциально разделять инфраструктуру перечисления между различными типами.

.
0
ответ дан 6 December 2019 в 05:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: