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

using System;

using System.Collections;

class MyClass {

// Этот итератор возвращает буквы А, В, С, D и Е. public IEnumerator GetEnumerator()    {

yield return 'A'; yield return 'B'; yield return 'C'; yield return 'D'; yield return 'E';

}

}

class ItrDemo5 {

static void Main() {

MyClass me = new MyClass();

foreach(char ch in me)

Console.Write(ch + " ");

Console.WriteLine();

}

}

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

А В С D Е

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

Создание именованного итератора

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

объект типа I Enumerable. Именно этот объект используется в коде для предоставления итератора. Именованный итератор представляет собой метод, общая форма которого приведена ниже:

public IEnumerable имя_итератора (список_параметров) {

// ...

yield return obj;

}

где имя_итератора обозначает конкретное имя метода; список_параметров — от нуля до нескольких параметров, передаваемых методу итератора; obj — следующий объект, возвращаемый итератором. Как только именованный итератор будет создан, его можно использовать везде, где он требуется, например для управления циклом

foreach.

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

// Использовать именованные итераторы.

using System;

using System.Collections;

class MyClass { char ch = 'A';

// Этот итератор возвращает буквы английского алфавита,

}

}

class ItrDemo4 {

static void Main() {

MyClass me = new MyClass ();

Console.WriteLine("Возвратить по очереди первые 7 букв:"); foreach(char ch in mc.MyItr(7))

Console.Write(ch + " ");

Console .WriteLine (lf\nlf) ;

Console.WriteLine("Возвратить по очереди буквы от F до L:"); foreach(char ch in mc.Myltr(5, 12))

Console.Write(ch + " ");

Console.WriteLine();

}

}

Эта программа дает следующий результат.

Возвратить по очереди первые 7 букв:

А В С D Е F G

Возвратить по очереди буквы от F до L:

F G Н I J К L

Создание обобщенного итератора

В приведенных выше примерах применялись необобщенные итераторы, но, конечно, ничто не мешает создать обобщенные итераторы. Для этого достаточно возвратить объект обобщенного типа IEnumerator<T> или IEnumerable<T>. Ниже приведен пример создания обобщенного итератора.

// Простой пример обобщенного итератора, using System;

using System.Collections.Generic;

class MyClass<T> {

T [ ] array;

public MyClass(T[] a) { array = a;

}

// Этот итератор возвращает символы из массива chrs. public IEnumetator<T> GetEnumerator()    {

foreach(T obj in array) yield return obj;

}

}

class GenericItrDemo { static void Main() {

int [ ] nums ={4, 3, 6, 4, 7, 9 };

MyClass<int> me = new MyClass<int>(nums);

foreach(int x in me)

Console.Write(x + " ");

Console.WriteLine();

bool[] bVals = { true, true, false, true };

MyClass<bool> mc2 = new MyClass<bool>(bVals);

foreach(bool b in mc2)

Console.Write(b + " ");

Console.WriteLine ();