Выбрать главу

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() ;

}

}

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

0123456789

0123456789

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

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

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

DictionaryEntry Entry { get; }

Свойство Entry позволяет получить пару "ключ-значение7' из перечислителя в форме структуры DictionaryEntry. Напомним, что в структуре DictionaryEntry определяются два свойства, Key и Value, с помощью которых можно получать доступ к ключу или значению, связанному с элементом коллекции. Ниже приведены два других свойства, определяемых в интерфейсе IDictionaryEnumerator.

object Key { get; } object Value { get; }

С помощью этих свойств осуществляется непосредственный доступ к ключу или значению.

Перечислитель типа IDictionaryEnumerator используется аналогично обычному перечислителю, за исключением того, что текущее значение в данном случае получается с помощью свойств Entry, Key или Value, а не свойства Current. Следовательно, приобретя перечислитель типа IDictionaryEnumerator, необходимо вызвать метод MoveNext (), чтобы получить первый элемент коллекции. А для получения остальных ее элементов следует продолжить вызовы метода MoveNext (). Этот метод возвращает логическое значение false, когда в коллекции больше нет ни одного элемента.

В приведенном ниже примере программы элементы коллекции типа Hashtable перечисляются с помощью перечислителя типа IDictionaryEnumerator.

// Продемонстрировать применение перечислителя типа IDictionaryEnumerator.

using System;

using System.Collections;

class IDicEnumDemo { static void Main() {

// Создать хеш-таблицу.

Hashtable ht = new Hashtable();

// Добавить элементы в таблицу, ht.Add("Кен", "555-7756"); ht.Add("Мэри", "555-9876"); ht.Add("Том", "555-3456"); ht.Add("Тодд", "555-3452");

// Продемонстрировать применение перечислителя.

IDictionaryEnumerator etr = ht.GetEnumerator();

Console.WriteLine("Отобразить информацию с помощью свойства Entry."); while(etF.MoveNext())

Console.WriteLine(etr.Entry.Key + ": " + etr.Entry.Value);

Console.WriteLine();

Console.WriteLine("Отобразить информацию " +

"с помощью свойств Key и Value.");

etr .Reset () ;

while(etr.MoveNext ())

Console.WriteLine(etr.Key + ": " + etr.Value);

}

}

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

Отобразить информацию с помощью свойства Entry.

Мэри: 555-9876 Том: 555-3456 Тодд: 555-3452 Кен: 555-7756

Отобразить информацию с помощью свойств Key и Value.

Мэри: 555-9876 Том: 555-3456 Тодд: 555-3452 Кен: 555-7756

Реализация интерфейсов IEnumerable и IEnumerator

Как упоминалось выше, для циклического обращения к элементам коллекции зачастую проще (да и лучше) организовать цикл foreach, чем пользоваться непосредственно методами интерфейса IEnumerator. Тем не менее ясное представление о принципе действия подобных интерфейсов важно иметь по еще одной причине: если требуется создать класс, содержащий объекты, перечисляемые в цикле foreach, то в этом классе следует реализовать интерфейсы IEnumerator и IEnumerable. Иными словами, для того чтобы обратиться к объекту определяемого пользователем класса в цикле foreach, необходимо реализовать интерфейсы IEnumerator и IEnumerable в их обобщенной или необобщенной форме. Правда, сделать это будет нетрудно, поскольку оба интерфейса не очень велики.