Скачать презентацию Оператор foreach итерационная переменная оператор foreach type identifier Скачать презентацию Оператор foreach итерационная переменная оператор foreach type identifier

6_3_C#_итераторы.pptx

  • Количество слайдов: 11

Оператор foreach итерационная переменная оператор foreach (type identifier in expression) statement тип итерационной переменной Оператор foreach итерационная переменная оператор foreach (type identifier in expression) statement тип итерационной переменной массив или коллекция ü Коллекция (expression) • должна иметь тип class, struct или interface; • в типе коллекции достаточно определить открытый экземплярный метод Get. Enumerator(). ü В типе, который возвращает метод Get. Enumerator(), должны быть определены • свойство Current { get; }, которое дает доступ к текущему элементу коллекции; • метод bool Move. Next(), который возвращает значение • true - если в коллекции еще есть элементы; • false - в противном случае. ü Тип свойства Current (тип элементов коллекции) должен допускать неявное

Соглашения о реализации итераторов ü При инициализации итератор(enumerator) позиционируется перед первым элементом коллекции. Вызов Соглашения о реализации итераторов ü При инициализации итератор(enumerator) позиционируется перед первым элементом коллекции. Вызов свойства Current в этой позиции порождает исключение. Необходимо вызвать Move. Next перед тем, как обратиться к Current. Метод Reset возвращает итератор в позицию инициализации. ü Метод Move. Next перемещает Current к следующему элементу. Свойство Current возвращает один и тот же объект до тех пор, пока не будет вызван один из методов Move. Next или Reset. ü Move. Next возвращает false, когда итератор позиционируется за последним элементом коллекции. Если вызов Move. Next возвращает false, следующий за ним вызов свойства Current бросает исключение. ü Итераторы используются только для чтения данных из коллекции, их нельзя использовать для изменения коллекции (нельзя изменять ссылки).

Интерфейсы System. IEnumerable и System. Collections. IEnumerator ü В классе, реализующем интерфейс IEnumerable, можно Интерфейсы System. IEnumerable и System. Collections. IEnumerator ü В классе, реализующем интерфейс IEnumerable, можно использовать оператор foreach. ü Интерфейс IEnumerable реализован в классе System. Array и классахколлекциях. public interface IEnumerable { IEnumerator Get. Enumerator(); } public interface IEnumerator { object Current {get; } bool Move. Next(); void Reset(); } ü Типы, реализующие интерфейс IEnumerator, называют итераторами или перечислителями (enumerators).

Реализация итератора. Пример ü В примере для класса Library. Class определен итератор, который осуществляет Реализация итератора. Пример ü В примере для класса Library. Class определен итератор, который осуществляет перебор читателей (объектов типа Reader) c непустым списком книг. partial class Library. Class : IEnumerable { static Array. List books = new Array. List(); Array. List readers = new Array. List(); class Readers. With. Books. Enumerator : IEnumerator { private int current = -1; Library. Class lib; public static Array. List Books { get { return books; } } public Array. List Readers { get { return readers; } } public object Current { get { return lib. Readers[current] ; } } public IEnumerator Get. Enumerator() { return new Readers. With. Books. Enumerator(this); } } public Readers. With. Books. Enumerator(Library. Class lib) { this. lib = lib; } public bool Move. Next() { while (current < lib. Readers. Count-1) { current++; Reader rd = lib. Readers[current] as Reader; if (rd. Reader_books. Count > 0) return true; } return false; } public void Reset() { current = -1; } partial class Reader : Person { public int id {get; set; } Array. List reader_books = new Array. List(); } public Array. List Reader_books { get { return reader_books; } } }

Именованные итераторы ü В классе можно реализовать несколько итераторов. ü В следующем примере в Именованные итераторы ü В классе можно реализовать несколько итераторов. ü В следующем примере в классе Library. Class определены два именованных итератора partial class Library. Class : IEnumerable { public IEnumerable Books. Iterator() { return books; } } public IEnumerable Readers. Iterator() { return readers; } ü В следующем примере оператор foreach выполняется для итератора по умолчанию и двух именованных итераторов Console. Write. Line("n Default Iterator"); foreach (object reader in lib) Console. Write. Line(reader); Console. Write. Line("n Books. Iterator"); foreach (Book book in lib. Books. Iterator()) Console. Write. Line(book); Console. Write. Line("n Readers. Iterator"); foreach (Reader reader in lib. Readers. Iterator()) Console. Write. Line(reader. To. Short. String());

Итераторы с параметрами ü Итераторы могут иметь параметры. В следующем примере в классе Library. Итераторы с параметрами ü Итераторы могут иметь параметры. В следующем примере в классе Library. Class определены два итератора с параметрами – один для перебора книг, год издания которых больше или равен значению параметра, другой для перебора книг, в названии которых есть заданная строка. partial class Library. Class : IEnumerable { public IEnumerable Books. Year. Iterator(int year) { foreach (Book book in books) { if (book. Year >= year) yield return book; } } } public IEnumerable Books. Sub. Title. Iterator(string sub. Title) { foreach (Book book in books) { if (book. Title. Contains(sub. Title)) yield return book; } } ü В следующем примере для этих итераторов выполняется оператор foreach (Book book in lib. Books. Year. Iterator(2008)) Console. Write. Line(book); foreach (Book book in lib. Books. Sub. Title. Iterator("C#")) Console. Write. Line(book);

Итерация с помощью оператора yield ü Для итератора, который выполняет итерацию по объекту класса Итерация с помощью оператора yield ü Для итератора, который выполняет итерацию по объекту класса с помощью оператора yield, компилятор автоматически создает методы Current, Move. Next и Dispose интерфейса IEnumerator или IEnumerator. Метод Reset() не поддерживается. Для повторной итерации необходимо получить новый итератор. ü Компилятор определяет для итератора вложенный класс, который отслеживает положения итератора, пока в клиентском коде выполняется цикл foreach. ü Ключевое слово yield можно использовать только в блоке итератора и только в одной из следующих форм: yield return ; yield break; ü Оператор yield return вычисляет выражение expression и возвращает значение объекту перечислителя; выражение expression должно допускать неявное преобразование к типу результата итератора. ü Оператор yield break завершает итерацию.

Оператор yield. Пример 1 ü В примере оператор yield используется в итераторе для перебора Оператор yield. Пример 1 ü В примере оператор yield используется в итераторе для перебора всех полей типа Book. partial class Book { public string Title { get; set; } public string Author { get; set; } public int Year { get; set; } public Book(string Title, string Author, int Year) { this. Title = Title; this. Author = Author; this. Year = Year; } } public IEnumerable Fields. Iterator() { Console. Write. Line("1"); yield return Title; Console. Write. Line("2"); yield return Author; Console. Write. Line("3"); yield return Year; Console. Write. Line("4"); } static void Main(string[] args) { Book bk = new Book("C#", "Эндрю Троелсен", 2005); foreach (object fld in bk. Fields. Iterator()) Console. Write. Line(fld); } Вывод: 1 C# 2 Эндрю Троелсен 3 2005 4

Оператор yield. Пример 2 ü В примере оператор yield используется в итераторе для перебора Оператор yield. Пример 2 ü В примере оператор yield используется в итераторе для перебора данных типа Reader. static void Main(string[] args) { partial class Reader : Person, IEnumerable { Reader r 1 = new Reader ( new Person("Ivan", "Ivanov", new Date. Time(1990, 1, 1)), public int id {get; set; } public Date. Time Registration. Date { get; private set; } Array. List reader_books = new Array. List(); } public IEnumerator Get. Enumerator() { int j = 0; Console. Write. Line("_1"); yield return id; Console. Write. Line("_2"); yield return Registration. Date; Console. Write. Line("_3"); foreach (Book book in reader_books) { Console. Write. Line("in foreach " + j++); yield return book; } Console. Write. Line(j); } 123, new Date. Time(2008, 01 , 09)); r 1. Add(new Book("C# ", "Trey Nash", 2010)); r 1. Add(new Book("C++", "Bjarn Straustroup", 2008)); foreach (object obj in r 1) Console. Write. Line(obj); } Вывод: _1 123 _2 09. 01. 2008 0: 00 _3 in foreach 0 C# Trey Nash 2010 in foreach 1 C++ Bjarn Straustroup 2008 2

Оператор yield. Пример 3 (выражение yeild break; ) ü В примере в классе Library. Оператор yield. Пример 3 (выражение yeild break; ) ü В примере в классе Library. Class определен итератор для перебора первых трех читателей с непустым списком книг. partial class Library. Class : IEnumerable { static Array. List books = new Array. List(); Array. List readers = new Array. List(); public IEnumerable First. Three. Readers. Iterator() { int j = 0; foreach (Reader reader in readers) { if ( j == 3) yield break; if (reader. Reader_books. Count > 0) { j++; yield return reader; } }

Ограничения на методы с оператором yield ü Оператор yield может располагаться только внутри блока Ограничения на методы с оператором yield ü Оператор yield может располагаться только внутри блока итератора. ü В методах, содержащих yield : • не допускается использование блоков unsafe; • параметры метода, оператора или метода доступа не могут иметь модификаторов ref или out; • выражение yield return не может размещаться в блоке catch или в блоке try, который имеет обработчики catch. ü Оператор yield не может использоваться в анонимных методах.