Вопрос о IEnumerable <T> - PullRequest
       37

Вопрос о IEnumerable <T>

3 голосов
/ 06 июля 2010

Я заметил, что IEnumerable (Generics) требует реализации 2 методов:

1. IEnumerator<T> GetEnumerator()

2. IEnumerable.GetEnumerator() Метод

(http://msdn.microsoft.com/en-us/library/19e6zeyy.aspx)

Что такое # 2 и как я должен определить / реализовать это?

Из-за того, что я поиграл с некоторым кодом, кажется, что IEnumerator GetEnumerator () вызывается в цикле foreach. Где в игру вступает # 2 IEnumerable.GetEnumerator?

Я просматривал рецепт 6.1 Создание итератора для универсального типа в книге рецептов C # 3.0 Oreilly, и я получал сообщение об ошибке, поскольку # 2 не было реализовано (его не включили в код рецепта).

Спасибо!

Ответы [ 7 ]

9 голосов
/ 07 июля 2010

Первый - это универсальный GetEnumerator, а второй - неуниверсальный. Функционально они выполняют ту же работу, но неуниверсальный может возвращать только тип object.

Самый простой способ реализовать это - реализовать универсальную версию, а затем предоставить ее для неуниверсальной версии:

IEnumerator IEnumerable.GetEnumerator() {
   return GetEnumerator();
}
2 голосов
/ 07 июля 2010

Неуниверсальный интерфейс IEnumerable используется для обратной совместимости, а также очень полезен для доступа к универсальному интерфейсу IEnumerable неуниверсальным образом.

Вы можете реализовать только член IEnumerable.GetEnumerator, а просто explicity реализовать другой интерфейс, такой как

IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); /*generic method call*/ }
1 голос
/ 07 июля 2010

Второй - для кода, написанного для .NET v1.1, который не понимает обобщений.

Как правило, вы просто возвращаете значение из универсального GetEnumerator ()

IEnumerator IEnumerable.GetEnumerator()
{
     return GetEnumerator();
}
1 голос
/ 07 июля 2010

Вам нужно только определить универсальный (который возвращает String в моем примере), а затем указать неуниверсальному методу GetEnumerator вызвать универсальный GetEnumerator (который возвращает Object.)

class Foo : IEnumerable<string>
{
    public IEnumerator<string> GetEnumerator()
    {
        foreach (string value in new[] { "a", "b", "c" })
        {
            yield return value;
        }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}
1 голос
/ 07 июля 2010

# 2 - это Явная неуниверсальная реализация метода GetEnumerator из интерфейса IEnumerable. # 1 в вашем примере - реализация GetEnumerator() для интерфейса IEnumerable<T>.

IEnumerable.GetEnumerator() может вызывать тот же базовый код, что и IEnumerable, просто он не так строго типизирован (возвращает объект вместо строго типизированного IEnumerator).

0 голосов
/ 07 июля 2010

Как правило, вам больше не нужно реализовывать IEnumerable самостоятельно. Есть множество встроенных классов в платформе, которые реализуют этот интерфейс различными способами, чтобы удовлетворить 99% ваших потребностей.

Однако, если вы хотите, метод IEnumerable, GetEnumerator () будет возвращать объект IEnumerator клиенту, вызывающему foreach. Этот объект Ienumerator является объектом, который отслеживает, какой элемент в коллекции является msgstr "один возвращается, когда foreach" повторяется ". Чтобы это работало, вы должны определить класс, который будет тем перечислителем (он должен реализовывать IEnumerator или, как правило, IEnumerator)

Как пример (для PersonCollection)

public IEnumerator GetEnumerator() { return new myTypeEnumerator(this); }
public class myTypeEnumerator : IEnumerator
{
    int nIndex;
    PersonCollection pers;
    public myTypeEnumerator(PersonCollection myTypes) 
     { pers = myTypes; nIndex = -1; }
    public bool MoveNext() { return (++nIndex < pers.alPers.Count); }
    public object Current { get { return (pers[nIndex]); } }
    public void Reset() { nIndex = -1; }
}

Единственная разница между этой и универсальной версией заключается в том, что универсальная версия строго типизирована:

public IEnumerator<T> GetEnumerator() { return new myTypeEnumerator<T>(this); }
public class myTypeEnumerator<T> : IEnumerator<T>
{
    int nIndex;
    IList<T> tList;
    public myTypeEnumerator(IList<T> listOfTs) 
     { 
        tList = listOfTs; 
        nIndex = -1; 
     }
    public bool MoveNext() { return (++nIndex < tList.Count); }
    public T Current { get { return (tList[nIndex]); } }
    public void Reset() { nIndex = -1; }
}
0 голосов
/ 07 июля 2010

Чтобы реализовать второй интерфейс, сделайте явную реализацию, которая просто вызывает неявную реализацию универсального интерфейса. Что-то вроде

class FooCollection : IEnumerable<Foo>, IEnumerable
{
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public IEnumerator<Foo> GetEnumerator()
    {
        // return enumerator
    }
}

Редактировать: Наследование от IEnumerable является избыточным, но этот ответ демонстрирует, что оба интерфейса должны быть реализованы при наследовании IEnumerable<T>, поскольку IEnumerable<T> происходит от IEnumerable.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...