Когда вызывается метод IEnumerator.Reset ()? - PullRequest
8 голосов
/ 16 октября 2010

давайте получим этот код:

class MyList : IEnumerable, IEnumerator
{
    int[] A = { 1, 2, 3, 4, 5 };
    int i = -1;

    #region IEnumerator Members

    public object Current
    {
        get { return A[i]; }
    }

    public bool MoveNext()
    {
        i++;
        return i < 5;
    }

    public void Reset()
    {
        i = -1;
    }

    #endregion

    #region IEnumerable Members

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

    #endregion
}

И в основном методе:

MyList list = new MyList();
foreach (int i in list)
{
    Console.WriteLine(i);
}

foreach (int i in list)
{
    Console.WriteLine(i);
}

Почему второй не работает ??и "я" не инициализируется снова ??

Это правда: метод Reset должен вызываться автоматически перед выполнением foreach ??

почему здесь не звонят ??

Ответы [ 5 ]

9 голосов
/ 16 октября 2010

Сброс избыточен;настолько, что требование в спецификации языка для блоков итераторов вызывает исключение при сбросе.Правильнее всего сделать, просто избавиться от старого итератора и снова вызвать GetEnumerator.Или лучше: избегайте наличия , чтобы прочитать его дважды, так как не все данные повторяются.

7 голосов
/ 16 октября 2010

IEnumerable и IEnumerator обычно должны быть отдельными классами, и, за исключением случая, когда перечислители всегда возвращают пустой или всегда возвращают один и тот же элемент, метод GetEnumerator должен всегда возвращать новый экземпляр IEnumerator.

Нет особого смысла в IEnumerator.Reset;циклы for-each не используют его, и потребители IEnumerable / IEnumerator не могут использовать его, если они не знают, что такое перечислимый тип, и в этом случае они могут использовать фактический тип, а не интерфейс.

3 голосов
/ 16 октября 2010

Сброс не вызывается foreach.Просмотр вашего метода Main в Reflector подтверждает это.

Классы .NET, такие как ArrayList, фактически возвращают новый экземпляр класса, который реализует IEnumerator.

Например, ArrayList реализуетIEnumerable, и его GetEnumerator метод выглядит следующим образом:

public virtual IEnumerator GetEnumerator()
{
    return new ArrayListEnumeratorSimple(this);
}

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

Для полного примера, показывающего реализацию IEnumerable и отдельный класс, реализующий IEnumerator, вы можете посмотреть документацию для IEnumerable .

2 голосов
/ 22 декабря 2011

Это также работает:

public bool MoveNext()
{
        if(i < 5)
        {
            i++;
            return true;
        }
        else
        {
            i = -1;
            return false;
        }
}
0 голосов
/ 14 октября 2013

Есть много случаев, когда мне нужно это сделать, поэтому я делаю вызов метода reset в моем методе GetEnumerator.Вот пример:

public IEnumerator GetEnumerator()
{
    this.Reset(); // Reset each time you get the Enumerator
    return (IEnumerator)this;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...