Ответ
Интерфейс System.Collections.IEnumerator (необобщенный) и его обобщенный аналог System.Collections.Generic.IEnumerator<T> определяют контракт для последовательного перебора элементов коллекции. Это основа работы цикла foreach.
Основные методы интерфейса IEnumerator:
-
bool MoveNext()- Назначение: Перемещает перечислитель к следующему элементу коллекции.
- Возвращаемое значение:
true, если перечислитель успешно перемещен к следующему элементу;false, если перечислитель достиг конца коллекции. - Важно: Перед первым вызовом
MoveNext()перечислитель позиционирован перед первым элементом коллекции. Первый вызов перемещает его на первый элемент.
-
void Reset()- Назначение: Устанавливает перечислитель в его начальное положение, которое находится перед первым элементом коллекции.
- Особенность: Не все реализации поддерживают этот метод. При вызове у неподдерживающего enumerator'а выбрасывается
NotSupportedException. В современном коде (IEnumerator<T>) его использование считается устаревшим.
-
object Current { get; }(Свойство)**- Назначение: Возвращает текущий элемент коллекции.
- Особенности:
- Свойство следует вызывать только после успешного вызова
MoveNext(). - Если перечислитель позиционирован перед первым элементом или после последнего, поведение свойства
Currentне определено (обычно бросается исключениеInvalidOperationException). - При каждом обращении возвращает один и тот же объект, пока не будет вызван
MoveNext().
- Свойство следует вызывать только после успешного вызова
Обобщенный интерфейс IEnumerator<T> наследует IEnumerator и IDisposable и добавляет:
T Current { get; }– типобезопасное свойство, возвращающее элемент типаT.void Dispose()– для освобождения ресурсов (например, закрытия открытого файла или соединения с БД, использованного при перечислении).
Практический пример: Реализация простого перечислителя:
public class CountdownEnumerator : IEnumerator<int>
{
private int _current;
private readonly int _start;
public CountdownEnumerator(int start)
{
_start = start;
Reset(); // Инициализируем позицию перед первым элементом
}
public int Current => _current;
object IEnumerator.Current => Current;
public bool MoveNext()
{
if (_current > 0)
{
_current--;
return true;
}
return false; // Достигнут конец
}
public void Reset()
{
_current = _start + 1; // Позиция ПЕРЕД первым элементом (start)
}
public void Dispose()
{
// В данном примере нечего освобождать
}
}
// Использование
var enumerator = new CountdownEnumerator(3);
while (enumerator.MoveNext())
{
Console.WriteLine(enumerator.Current); // Выведет: 3, 2, 1
}
Итог: MoveNext() и Current — это минимально необходимые методы для поддержки перечисления. Reset() используется редко, а Dispose() в IEnumerator<T> важен для корректного управления ресурсами.