class My: IEnumerable
{
public IEnumerator GetEnumerator()
{
yield return "one";
yield return "two";
yield return "three";
yield return "ААА!!!";
}
}
class Program
{
static void Main(string[] args)
{
foreach (string s in new My()) Console.WriteLine(s);
Console.ReadKey(); } }
//Итератор, перебирающий значения в заданном диапазоне (От 1 до 5)
class Program
{
public static IEnumerable Count(int from, int to)
{
from =1;
while (from <= to) yield return from++;
}
static void Main(string[] args)
{
foreach (int i in Count(1,5)) Console.WriteLine(i);
Console.ReadKey(); } }
Преимущество использования итераторов заключается в том, что для одного и того же класса можно задать различный порядок перебора элементов.
Модернизируем пример с массивом монстров и демонов, добавив в код программы две дополнительные стратегии перебора элементов класса Mas_Monster - перебор в обратном порядке и выборка только тех объектов, которые являются экземплярами класса Monster (для этого используется метод получения типа объекта GetType()).
class Monster {…}
class Daemon: Monster {…}
class Mas_Monster: IEnumerable
{
Monster[] mas;
int n;
public Mas_Monster()
{
mas = new Monster[10];
n = 0;
}
public IEnumerator GetEnumerator()
{
for (int i = 0; i < n; i++) yield return mas[i];
}
Перебор в обратном порядке!!!
public IEnumerable Backwards()
{
for (int i = n-1; i >= 0; i--) yield return mas[i];
}
Перебор только монстров!!!
public IEnumerable MonsterOnly()
{
for (int i = 0; i < n; i++)
Метод GetType().Name возвращает имя типа
if (mas [i].GetType().Name=="Monster")
yield return mas[i];
}
public void Add(Monster m)
{
if (n >= 10) return;
mas[n] = m;
n++;
}
}
class Program
{
static void Main(string[] args)
{
Mas_Monster m = new Mas_Monster();
m.Add(new Monster(10, 10, "Вася"));
m.Add(new Daemon (10, 10, "Вася", 5));
Console.WriteLine(" Все монстры и демоны ");
foreach (Monster x in m)
x.Passport();
Console.WriteLine(" Все монстры и демоны в обратном порядке их следования в массиве ");
foreach (Monster x in m.Backwards())
x.Passport();
Console.WriteLine(" Только монстры! ");
foreach (Monster x in m.MonsterOnly())
x.Passport();
Console.ReadKey(); } }
Блок итератора синтаксически представляет собой обычный блок и может использоваться в теле метода, операции, части свойства get, если соответствующее возвращаемое значение имеет тип IEnumerable или IEnumerator. В теле блока итератора могут встречаться две конструкции:
Yield return формирует значение, выдаваемое на очередной итерации
Yield break – завершение итерации
Ключевое слово yield имеет специальное значение для компилятора только в таких конструкциях.
Код блока итератора выполняется не так, как обычные блоки. Компилятор формирует объект-перечислитель, при вызове метода MoveNext() которого выполняется код блока итератора, выдающий очередное значение с помощью слова yield. Следующий вызов метода MoveNext() объекта-перечислителя возобнавляет выполнение блока итератора с момента, на которм он был приостановлен в предыдущий раз.