В интерфейсе IEnumerator определяются два метода. Первым из них является метод MoveNext () , объявляемый следующим образом.
Bool MoveNext()
При каждом вызове метода MoveNext () текущее положение перечислителя смещается к следующему элементу коллекции. Этот метод возвращает логическое значение true, если следующий элемент коллекции доступен, и логическое значение false, если достигнут конец коллекции. Перед первым вызовом метода MoveNext () значение свойства Current оказывается неопределенным. (В принципе до первого вызова метода MoveNext () перечислитель обращается к несуществующему элементу, который должен находиться перед первым элементом коллекции. Именно поэтому приходится вызывать метод MoveNext () , чтобы перейти к первому элементу коллекции.)
Для установки перечислителя в исходное положение, соответствующее началу коллекции, вызывается приведенный ниже метод Reset ().
Void Reset()
После вызова метода Reset () перечисление вновь начинается с самого начала коллекции. Поэтому, прежде чем получить первый элемент коллекции, следует вызвать метод MoveNext().
В интерфейсе IEnumerator<T> методы MoveNext () и Reset () действуют по тому же самому принципу.
Необходимо также обратить внимание на два следующих момента. Во-первых, перечислитель нельзя использовать для изменения содержимого перечисляемой с его помощью коллекции. Следовательно, перечислители действуют по отношению к коллекции как к доступной только для чтения. И во-вторых, любое изменение в перечисляемой коллекции делает перечислитель недействительным.
Применение обычного перечислителя
Прежде чем получить доступ к коллекции с помощью перечислителя, необходимо получить его. В каждом классе коллекции для этой цели предоставляется метод GetEnumerator () , возвращающий перечислитель в начало коллекции. Используя этот перечислитель, можно получить доступ к любому элементу коллекции по очереди. В целом, для циклического обращения к содержимому коллекции с помощью перечислителя рекомендуется придерживаться приведенной ниже процедуры.
Получить перечислитель, устанавливаемый в начало коллекции, вызвав для этой коллекции метод GetEnumerator ().
Организовать цикл, в котором вызывается метод MoveNext (). Повторять цикл до тех пор, пока метод MoveNext () возвращает логическое значение true.
Получить в цикле каждый элемент коллекции с помощью свойства Current.
Ниже приведен пример программы, в которой реализуется данная процедура. В этой программе используется класс ArrayList, но общие принципы циклического обращения к элементам коллекции с помощью перечислителя остаются неизменными для коллекций любого типа, в том числе и обобщенных.
// Продемонстрировать применение перечислителя.
Using System;
Using System.Collections;
class EnumeratorDemo { static void Main() {
ArrayList list = new ArrayList(1);
for(int i=0; i < 10; i++) list.Add(i);
// Использовать перечислитель для доступа к списку.
IEnumerator etr = list.GetEnumerator(); while(etr.MoveNext ())
Console.Write(etr.Current + " ") ;
Console.WriteLine() ;
// Повторить перечисление списка.
Etr .Reset () ;
While(etr.MoveNext())
Console.Write(etr.Current + " ") ;
Console.WriteLine() ;
}
}
Вот к какому результату приводит выполнение этой программы.
Вообще говоря, для циклического обращения к элементам коллекции цикл foreach оказывается более удобным, чем перечислитель. Тем не менее перечислитель предоставляет больше возможностей для управления, поскольку его можно при желании всегда установить в исходное положение.
Применение перечислителя типа IDictionaryEnumerator
Если для организации коллекции в виде словаря, например типа Hashtable, реализуется необобщенный интерфейс IDictionary, то для циклического обращения к элементам такой коллекции следует использовать перечислитель типа IDictionaryEnumerator вместо перечислителя типа IEnumerator. Интерфейс IDictionaryEnumerator наследует от интерфейса IEnumerator и имеет три дополнительных свойства. Первым из них является следующее свойство.
DictionaryEntry Entry { get; }
Свойство Entry позволяет получить пару "ключ-значение7' из перечислителя в форме структуры DictionaryEntry. Напомним, что в структуре DictionaryEntry определяются два свойства, Key и Value, с помощью которых можно получать доступ к ключу или значению, связанному с элементом коллекции. Ниже приведены два других свойства, определяемых в интерфейсе IDictionaryEnumerator.
object Key { get; } object Value { get; }