Г. Шилдт - С#4.0 Полное руководство (1160795), страница 205
Текст из файла (страница 205)
АВСВ АВСВ Глава 25. Комекции, веречисвитеви и игерагоры 1003 В данной программе сначала создается класс МуС1аяя, в котором инкапсулируется небольшой массив типа спаг, состоящий из символов )(-(). Индекс этого массива хранится в переменной 1с(х, инициализируемой значением — 1. Затем в классе МуС1аяя реализуются оба интерфейса, 1Елшпегасог и 1ЕлывегаЬ1е. Метод СеГЕпнмегасог () возвращает ссылку на перечислитель, которым в данном случае оказывается текущий объект. Свойство Саггелс возвращает следующий символ в массиве, т.е.
объект, указываемый по индексу 1с(х. Метод Моненехс ( ) перемещает индекс ьг(х в следующее положение. Этот метод возвращает логическое значение га1яе, если достигнут конец коллекции, в противном случае — логическое значение ггне. Напомним, что перечислитель оказывается неопределенным вплоть до первого вызова метода Моненехс ( ) . Следовательно, метод Моненехс () автоматически вызывается в цикле гогеасЬ перед обращением к свойству Сиггепс. Именно поэтому первоначальное значение переменной 1с(х устанавливается равным -1.
Оно становится равным нулю на первом шаге цикла 1огеасЬ. Обобщенная реализация рассматриваемых здесь интерфейсов будет действовать по тому же самому принципу. Далее в методе ма1п () создается объект мс типа мус1аяя, и содержимое этого объекта дважды отображается в цикле ЕогеасЬ. Применение итераторое Как следует из предыдущих примеров, реализовать интерфейсы 1Епшпегатог и 1Епивегабуе нетрудно. Но еще проще воспользоваться ите)яаторол, который представляет собой метод, оператор или аксессор, возвращающий по очереди члены совокупности объектов от ее начала и до конца.
Так, если некоторый массив состоит из пяти элементов, то итератор данного массива возвратит все эти элементы по очереди. Реализовав итератор, можно обращаться к объектам определяемого пользователем класса в цикле 1огеасЬ. Обратимся сначала к простому примеру итератора. Приведенная ниже программа является измененной версией предыдущей программы, в которой вместо явной реализации интерфейсов 1Епнмегагог и 1ЕпивегаЬ1е применяется итератор. // Простой пример применения итеряторя.
яягпч Буягепч нагло Буяпеи.со11еспгопя; с1аяя МуС1яяя ( сваг() свгя = ( 'Я', 'В', 'С', 'П' Этот итерятор возвращает символы ия массива слгя. рнвггс гкпшпегятог Сескяниегасог() ( Гогеасп(с)паг с(п гл с)1гя) уге16 гегагл с)1; ) ) с1аяя 1ггоеио ( япясгс ноЫ Ма1л() МуС1аяя ис = лен МуС1аяя() 1004 Часть П. Библиотека С(г Гогеасп (спас сь 1п щс) Сопяо1е.нг11е(сп + " Сопяо1е.нгггеььпе() При выполнении этой программы получается следующий результат.
АВСП Как видите, содержимое массива щс. С)згя перечислено. Рассмотрим эту программу более подробно. Во-первых, обратите внимание на то, что в классе мус1аяя не указывается 1еппщегасог в качестве реализуемого интерфейса. При создании итератора компилятор реализует этот интерфейс автоматически. И во-вторых, обратите особое внимание на метод сегеппщегасог (), который ради удобства приводится ниже еще раз. Этот итератор возвращает символы из массива сьгя.
роь11с ?Епсщогасог Соокпощсгаоог() Гогеасв(спад сп гп свгя) уье1б гегогп сЬг ) Это и есть итератор для объектов класса МуС1аяя. Как видите, в нем явно реализуется метод СеСЕпсщегасог (), определенный в интерфейсе 1Еппщега)з1е. А теперь перейдем непосредственно к телу данного метода. Оно состоит из цикла гогеас)з, в котором возвращаются элементы из массива с)з ге.
И делается это с помощью оператора уфе1б гессгп. Этот оператор возвращает следующий объект в коллекции, которым в данном случае оказывается очередной символ в массиве СЬгя. Благодаря этому средству обращение к объекту щс типа МуС1ая я организуется в цикле гогеас)з внутри метода Маьп () . Обозначение уье1В служит в языке СФ в качестве контекстного клнг ~свого слова. Это означает, что оно имеет специальное назначение только в блоке итератора. А вне этого блока оно может быть использовано аналогично любому другому идентификатору. Следует особо подчеркнуть, что итератор не обязательно должен опираться на массив или коллекцию другого типа.
Он должен просто возвращать следующий элемент из совокупности элементов. Это означает, что элементы могут быть построены динамически с помощью соответствующего алгоритма. В качестве примера ниже приведена версия предыдущей программы, в которой возвращаются все буквы английского алфавита, набранные в верхнем регистре. Вместо массива буквы формируются в цикле 1ог. О Пример линамического построения значений, возвращаемых по очереди с помощью итератора. оя1пэ Яуясещ; оя1пэ Зуясещ.Со11есгсопяг с1аяв НуС1аяя сваг сл = 'А'; О Этот итератор возвращает буквы английского О алфавита, набранные в верхнем регистре.
Глава 25. Коллекции, перечисаитеаи и игераторы 1005 рпвуьс 1Еппщегапог оеГЕппщегааог() ( гог(зпа 1=0) 1 < 2тп 1++) ууе1д геапгп (сьаг) (сЬ ) ) а1аяя 1пгоещо2 ( яааа1с ко1д Маап() МуС1аяя щс = пен МуС1аяя() гогеааь(сьаг сЬ уп тс) Сопяо1е.нгусе(аЬ + " ") Сопяо1е.нгзаекьпе()) ) ) Вот к какому результату приводит выполнение этой программы. а В с 0 е Р о н 1 3 к ь м н О Р я а 5 т 0 ч н х т 3 Прерывание итератора Для преждевременного прерывания итератора служит следующая форма оператора ууе1с). ууе1д Ьгеа)с) Когда этот оператор выполняется, итератор уведомляет о том, что достигнут конец коллекции.
А это, по существу, останавливает сам итератор. Приведенная ниже программа является версией предыдущей программы, измененной с целью отобразить только первые десять букв английского алфавита. О Пример прерывания итератора. пя1пэ Буяпеп|Г пяьпч Яуясещ.Со11есп1опя; с1аяя Муа1аяя ( аьаг сЬ = 'К') /У Этот итератор возвращает первые 10 букв английского алфавита.
рпЬ11с 1Епсщегасог СеГЕппщегасог() ( Гог(упп 1=0) г < 2б) 1++) ( 11(1 == 10) ууе1д Ьгеа)п // прервать итератор преждевременна уте1д геапгп (сьаг) (сЬ + с1аяя гпгОещоз ( яааага топи Ма1п() ( МуС1аяя ща = пен МуС1аяя()," гогеась(сьаг сЬ 1п щс) 1006 Часть И. Биби(отека С() Сопяо1е.иг) ге(сь + " ") г Сопяо1е.нгьгеьтпе() Эта программа дает следующий результат. АВСОЕЕЕН1 Применение нескольких операторов ухе16 В итераторе допускается применение нескольких операторов упе1б. Но каждый такой оператор должен возвращать следующий элемент в коллекции.
В качестве примера рассмотрим следующую программу. Пример применения нескольких операторов уье1с). пягпо Зуяпепи пя1по Буясеи.Со11еспгопя; с1аяя МуС1аяя ( О Этот итератор яояпраеает буквы А, В, с, О и е. рпЬ11с 1Еппиегагог Сегкппиегапог() ( уге1б гегпгп 'А'1 уге1С гегпгп 'В'; уье1С геппгп 'С'; уье1С гегпгп 'О'; уье1С геппгп с1аяя 1пгоеиоз ( ягаггс ппо1б Ма1п() ( МуС1аяя ис = пен МуС1аяя()г Гогеась(сьаг сЬ пп ис) Сопяо1е.иггге(сь т " "); Сопяо1е.нг1пеьппе()г Ниже приведен результата выполнения этой программы.
А В С ОЕ В данной программе внутри метода СеСЕппгпегагог () выполняются пять операторов у1е1б. Следует особо подчеркнуть, что они выполняются по очереди и каждый раз, когда из коллекции получается очередной элемент. Таким образом, на каждом шаге цикла гогеас)г в методе Магп () возвращается только один символ. Создание именованного итератора В приведенных выше примерах был продемонстрирован простейший способ реализации итератора.
Но ему имеется альтернатива в виде именованного итератора. В данном случае создается метод, оператор или аксессор, возвращающий ссылку на Глава 25. Камекции, аеречисаитеаи и итераторы 1007 объект типа 1ЕпстегаЬ1е. Именно этот объект используется в коде для предоставления итератора. Именованный итератор представляет собой метод, общая форма которого приведена ниже; рпЬ11с 1ЕпотегаЫе имя итератора(список параметров) ( О у1егб гегогп оЬу) ) где имя итера тора обозначает конкретное имя метода; список параметров — от нуля до нескольких параметров, передаваемых методу итератора; оЬ7' — следующий обьект, возвращаемый итератором.
Как только именованный итератор будет создан, его можно использовать везде, где он требуется, например для управления циклом уогеасЬ. Именованные итераторы оказываются весьма полезными в некоторых ситуациях, поскольку они позволяют передавать аргументы итератору, управляющему процессом получения конкретных элементов из коллекции.
Например, итератору можно передать начальный и конечный пределы совокупности элементов, возвращаемых из коллекции итератором. Эту форму итератора можно перегрузить, расширив ее функциональные возможности. В приведенном ниже примере программы демонстрируются два способа применения именованного итератора для получения элементов коллекции.
В одном случае элементы перечисляются в заданных начальном и конечном пределах, а в другом — элементы перечисляются с начала последовательности и до указанного конечного предела. // Использовать именованные итераторы. пягпэ Буясещ) ОЯ1ПС Буясещ.Со11ессгопя) с1аяя МуС1аяя ( сЬаг сЬ = 'А'; Этот итератор возвращает буквы английского алфавита, начиная с буквы А и кончая указанным конечным пределом. рпЬ1гс 1ЕпощегаЫе Му11г(1пГ епб) гог(1пс г=б) 1 < епб) г++) у1е1б гегогп (сьаг) (сь + 1)) ) этот итератор возвращает буквы в заданных пределах. рсЫгс 1ЕпощегаЫе Му11г(1пс Ьесгп, 1пс епб) ( гог(гпг г=Ьедяп) г < епб; гть) у1е1б гесигп (сЬаг) (сЬ + г); ) ) с1аяя 1сгОещо4 яса11с чо1б Ма1п() ( МуС1аяя щс = пен МуС1аяя(); Сопяо1е.нг1Геь1пе("Возвратить по очереди первые 7 букв:")," гогеасЬ(сЬаг сЬ гп щс.ну11г(7)) 1008 Часть!1.
Библиотека С№ Сопяо1е.иг1се(сЬ .ь " "); Сопяо1е Иг1сеЬ1пе("1п")) Сопяо1е.иггсеЬЬпе("Возвратить по очереди буквы от Г до Ь:"); Гогеась(сьаг сЬ гп щс.ну1<г(5, 12)) Сопяо1е.иг1се(сЬ ь " "); Сопяо1е.игьсеЬЬпе() ) ) Эта программа дает следующий результат. Возвратить по очереди первые 7 букв: А В С О Е Р С Возвратить по очереди буквы от Е до Ь: Г С Н 1 З К Ь Создание обобщенного итератора В приведенных выше примерах применялись необобщенные итераторы, но, конечно, ничто не мешает создать обобщенные итераторы. Для этого достаточно возвратить объект обобщенного типа 1Еппщегасог<Т> или 1ЕппщегаЬ1е<Т>, Ниже приведен пример создания обобщенною итератора. !/ Простой пример обобщенного итератора. пя1пч Зуягещ; пягпч Зуясещ.Со11ессгопя.сепеггс; с1аяя МуС1аяя<Т> ( Т[) актау! рчЬ11с МуС1аяя(Т[! а) ( аггау = а; ) О Этот итератор возвращает симвопы из массива свгя.
рпь11с 1епчщегагог<т> сесеплпегагог() гогеасЬ(Т оЬб гп аггау) у1е1б геспгп оЬЭЬ ) с1аяя Сепег1с1сгоещо ( ясаг1с чо1О Магп() Тпс[) пчщя = ( 4, 3, б, 4, 7, 9 ); Мус1аяя<1пс> щс = пеы МуС1аяя<1пс>(пщяя) Гогеасв(1пг х 1п щс) Сопяо1е.иг).се(х + " "); Глава 25. Коллекции, перечислители и итераторы 1009 Ссняс1е.игтвеьтпе(); Ьсс1(] Ьуя1я = ( Ггсе, Ггне, Га1яе, Ггие МуС1аяя<Ьсс1> шс2 = вен Мус1аяя<Ьсс1>(ЬЧв1я) Гсгевса(Ьсс1 Ь яе ес2) Совяс1е.нг1се(Ь в " ")) Ссняс1е.нгяееььпе(); Вот к какому результату приводит выполнение этой программы. 436479 Тгне тгне Га1яе Тгсе В данном примере массив, состоящий из возвращаемых по очереди объектов, передается конструктору класса МуС1 а я я. Тип этого массива указывает в качестве аргумента типа в конструкторе класса МуС1аяя.
Метод СеСЕпс7вегагог () оперирует данными обобщенного типа т и возвращает перечислитель типа тепимегасог<т>. Следовательно, итератор, определенный в классе МуС1ая в, способен перечислять данные любого типа. Инициализаторы комекций В СФ имеется специальное средство, называемое инициализан)оровт коллекции и упрощающее инициализацию некоторых коллекций. Вместо того чтобы явно вызывать метод Аг)г) ( ), при создании коллекции можно указать список инициализаторов. После этого компилятор организует автоматические вызовы метода Аг)с( (), используя значения из этого списка. Синтаксис в данном случае ничем не отличается от инициализации массива.