В обеих формах свойства Current получается текущий перечисляемый элемент коллекции. Но поскольку свойство Current доступно только для чтения, то перечислитель может служить только для извлечения, но не видоизменения объектов в коллекции.

В интерфейсе IEnumerator определяются два метода. Первым из них является метод MoveNext(), объявляемый следующим образом.

bool MoveNext()

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

Для установки перечислителя в исходное положение, соответствующее началу коллекции, вызывается приведенный ниже метод Reset().

void Reset()

После вызова метода Reset() перечисление вновь начинается с самого начала коллекции. Поэтому, прежде чем получить первый элемент коллекции, следует вызвать метод MoveNext().

В интерфейсе IEnumerator методы MoveNext() и Reset() действуют по тому же самому принципу.

Необходимо также обратить внимание на два следующих момента. Во-первых, перечислитель нельзя использовать для изменения содержимого перечисляемой с его помощью коллекции. Следовательно, перечислители действуют по отношению к коллекции как к доступной только для чтения. И во-вторых, любое изменение в перечисляемой коллекции делает перечислитель недействительным.

Применение обычного перечислителя

Прежде чем получить доступ к коллекции с помощью перечислителя, необходимо получить его. В каждом классе коллекции для этой цели предоставляется метод GetEnumerator(), возвращающий перечислитель в начало коллекции. Используя этот перечислитель, можно получить доступ к любому элементу коллекции по очереди. В целом, для циклического обращения к содержимому коллекции с помощью перечислителя рекомендуется придерживаться приведенной ниже процедуры.

1.    Получить перечислитель, устанавливаемый в начало коллекции, вызвав для этой коллекции метод GetEnumerator().

2.    Организовать цикл, в котором вызывается метод MoveNext(). Повторять цикл до тех пор, пока метод MoveNext() возвращает логическое значение true.

3.    Получить в цикле каждый элемент коллекции с помощью свойства 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();

  }

}

Вот к какому результату приводит выполнение этой программы.

0 1 2 3 4 5 6 7 8 9

0 1 2 3 4 5 6 7 8 9

Вообще говоря, для циклического обращения к элементам коллекции цикл foreach оказывается более удобным, чем перечислитель. Тем не менее перечислитель предоставляет больше возможностей для управления, поскольку его можно при желании всегда установить в исходное положение.

Применение перечислителя типа IDictionaryEnumerator

Если для организации коллекции в виде словаря, например типа Hashtable, реализуется необобщенный интерфейс IDictionary, то для циклического обращения к элементам такой коллекции следует использовать перечислитель типа IDictionaryEnumerator вместо перечислителя типа IEnumerator. Интерфейс IDictionaryEnumerator наследует от интерфейса IEnumerator и имеет три дополнительных свойства. Первым из них является следующее свойство.

Перейти на страницу:

Похожие книги