
- •Стандартные интерфейсы. Клонирование. Итераторы Стандартные интерфейсы .Net
- •Сравнение объектов (интерфейс iComparable)
- •Пример использования стандартного интерфейса iComparable на примере класса Monster
- •Сортировка объектов по различным критериям (интерфейс iComparer)
- •Пример использования стандартного интерфейса iComparer на примере класса Monster
- •Int сила, умение;
- •Клонирование объектов (интерфейс iCloneable)
- •Int сила, умение;
- •Перебор элементов (интерфейс iEnumerable) и итераторы
- •Пример работы класса с итератором
- •Int сила, умение;
- •Примеры применения простейших итераторов
Примеры применения простейших итераторов
//Итератор, перебирающий 4 заданные строки
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() объекта-перечислителя возобнавляет выполнение блока итератора с момента, на которм он был приостановлен в предыдущий раз.