1629295403-b876e2087bddebea4bc9666fb2377a02 (846199), страница 92
Текст из файла (страница 92)
главу 15, "Обобщенное программирование").468Часть VII. Дополнительные главыВывод п р о г р а м м ы п р о с т и э л е г а н т е н :ИщемвозрастLisaВозрастLisaНажмите<Enter>В-10длязавершенияпрограммы...качестве о т с т у п л е н и я — интерфейсляющийцелыйиндексаторвформеIListobjectописывает класс,t h i s [int].ВпредоставС# имеетсятакже и н т е р ф е й с I L i s t < T > , к о т о р ы й позволяет заменить o b j e c t выбранным вами типом Т.
Это устраняет необходимость преобразования типов изпредыдущего примера.Помните код функции M a i n ( ) , написанный при демонстрации самостоятельно разработанного класса L i n k e d L i s t ? (Его можно найти в демонстрационной программеL i n k e d L i s t C o n t a i n e r на прилагаемом компакт-диске.) Вот его фрагмент:publics t a t i cvoidMain ( s t r i n g []args){// Создаем к о н т е й н е р и д о б а в л я е м вL i n k e d L i s t 11с = new L i n k e d L i s t ( ) ;// Добавляем о б ъ е к т ы .
. .Console.WriteLine("ПроходLinkedListlteratorH i=понегоконтейнерутриэлементавручную");(LinkedListlterator)11с.GetEnumerator();Hi . R e s e t ();while ( H i .MoveNext () ){string s=( s t r i n g ) Hi . C u r r e n t ;Console.WriteLine(s);}Данный код получает L i n k e d L i s t l t e r a t o r и использует его метод M o v e N e x t ( )и свойство C u r r e n t для обхода связанного списка. Однако С# 2.0 может упростить вамэтот обход так, что вы получите перечисленные преимущества.Вам не придется вызывать G e t E n u m e r a t o r () (и выполнять преобразование типа результатов).Вам н е понадобится вызывать M o v e N e x t ( ) .Вам не придется вызывать C u r r e n t и выполнять преобразование типа, возвращаемого значения.Вы сможете просто использовать f o r e a c h для обхода коллекции (С# сделает всеостальное за вас).Если быть честным, то f o r e a c h работает и для класса L i n k e d L i s t из этой главы.
Это связано с наличием метода G e t E n u m e r a t o r ( ) . Но я все еще должен самостоятельно писать класс L i n k e d L i s t l t e r a t o r . Новизна состоит в том, чтовы можете пропустить при обходе часть вашего класса.Глава 20. Работа с коллекциями469В создаваемых классах коллекций можно предоставить блок итератора (iterateblock) вместо написания собственного класса итератора для поддержки коллекции.Можно использовать блок итератора и для других рутинных работ.Этот новый подход применяет блоки итераторов. Когда вы пишете класс коллекции,такой как K e y e d L i s t или P r i o r i t y Q u e u e — вы реализуете блок итератора вместореализации интерфейса I E n u m e r a t o r .
Затем пользователи этого класса могут простоитерировать коллекцию с помощью цикла f o r e a c h . Приготовьтесь расстаться с частьювашего драгоценного времени, чтобы ознакомиться с несколькими вариантами блоковитераторов.Все примеры в этом разделе являются частью демонстрационной программ ы I t e r a t o r B l o c k s н а прилагаемом компакт-диске.// I t e r a t o r B l o c k s - демонстрация применения блоков// итераторов для написания итераторов коллекцийusingSystem;namespaceIteratorBlocks{classIteratorBlocks{//Main - демонстрация//итераторовs t a t i cvoidпятиMain(string[]различныхприложенийблоковargs){// Итерирование месяцев года,вывод// каждом из нихM o n t h D a y s md = new M o n t h D a y s ( ) ;//ИтерируемколичестваднейвConsole.WriteLine("Месяцы:\n");foreach(stringsMonthinmd){Console.WriteLine(sMonth);}// Итерируем коллекцию строкS t r i n g C h u n k s sc = new S t r i n g C h u n k s ( ) ;// Итерируем - выводим т е к с т ,помещая// в с в о е й с о б с т в е н н о й с т р о к еConsole.WriteLine("\Строки:\п");foreach( s t r i n g sChunk in sc)каждыйфрагмент{Console.WriteLine(sChunk);}/ / А теперь выводим их в одну строкуConsole.WriteLine("\пВывод водну с т р о к у : \ п " ) ;foreach( s t r i n g sChunk in sc){Console.Write(sChunk);}Console.WriteLine();// Итерируем простые470числадо13Часть VII.
Дополнительные главыY i e l d B r e a k E x yb = new Y i e l d B r e a k E x ( ) ;// Итерируем,останавливаясь после 13Console.WriteLine("\пПростыечисла:\n");foreach(int nPrimei n yb)Console.WriteLine(nPrime);}// И т е р и р у е м ч е т н ы е ч и с л а в убывающем п о р я д к еEvenNumbers en = new E v e n N u m b e r s ( ) ;// Вывод четных ч и с е л от 10 до 4Console.WriteLine("\пЧетныечисла:\п");foreach(int nEven in en.DescendingEvens(11,3))Console.WriteLine(nEven);}// Итерируем числа типа doubleP r o p e r t y l t e r a t o r p r o p = new P r o p e r t y l t e r a t o r ( ) ;Console.WriteLine("\пЧислаdouble:\n");foreach(double db in prop.DoubleProp)Console.WriteLine(db);}}}// Ожидаем п о д т в е р ж д е н и я п о л ь з о в а т е л яConsole.WriteLine("Нажмите <Enter> для " +"завершения программы...");Console.Read();//Классы I t e r a t o r B l o c k s// MonthDays - определяем и т е р а т о р ,который возвращает// м е с я ц ы и к о л и ч е с т в о д н е й в нихclassMonthDays{string[]months ={"January 31","February 28","March 3 1 " ,"April 30","May 3 1 " ,"June 30","July 31","August 3 1 " ,"September 30","October 31","November 30","December 31"};//GetEnumerator - это и есть итераторpublicSystem.Collections.IEnumerator GetEnumerator(){foreach(stringsMonthinmonths){}}}// Возвращаем по одномуy i e l d r e t u r n sMonth;////StringChunks//фрагментыclass-определениемесяцу в каждойНовый с и н т а к с и ситератора,итерациивозвращающеготекстаStringChunks{//GetEnumerator - итератор.
Обратите//(дважды)вызывается в MainГлава 20. Работа с коллекциямивнимание,какон471publicSystem.Collections.IEnumeratorGetEnumerator(){//yieyieyieyieyieВозврат разных фрагментовld return"Using i t e r a t o rld return"blocks";ld return" i s n ' tall";ld return"thathard";ldreturn".";текста";накаждойитерации}}//YieldBreakEx//yieldclass-примериспользованияключевогословаbreakYieldBreakEx{i n t [ ] p r i m e s = { 2, 3, 5, 7,11, 13,17, 19, 23 };/ / G e t E n u m e r a t o r - возврат последовательности простых// чисел с демонстрацией применения конструкции y i e l d//breakpublicSystem.Collections.IEnumerator GetEnumerator(){foreach(intnPrimeinprimes){}}}if(nPrime >yieldreturn//EvenNumbers//числаclassмежду-13)yieldnPrime;числовойграничнымиbreak;итератор,//НовыйсинтаксисвозвращающийзначениямивчетныеубывающемпорядкеEvenNumbers{//DescendingEvens - "именованный" итератор,который// также демонстрирует использование конструкции y i e l d//breakpublicSystem.Collections.IEnumerable{DescendingEvens(int nTop,i n t nStop)// Начинаем с ближайшего к nTop меньшего ч е т н о г о числаif(nTop % 2!= 0)nTop -= 1;// Итерируем до ближайшего к n S t o p четного// превышающего э т о з н а ч е н и еf o r ( i n t i = n T o p ; i >= n S t o p ; i -= 2)числа,{if(i < n S t o p )yieldbreak;// Возвращаем на//числоyieldreturni;}}итерацииочередноечетноедоступасвойства}//Propertylterator // класса в качестве472каждойреализация функцииблока итератораЧасть VII.
Дополнительные главыclassPropertylterator{doublet]doubles ={1.0,2.0,3.5,4.67};// D o u b l e P r o p - с в о й с т в о"get" с блоком итератораpublicSystem.Collections.IEnumerableDoublePropget{foreach(doubledbindoubles){yieldreturndb;}Итерация месяцевСледующий фрагмент из демонстрационной программыI t e r a t o r B l o c k s предоставляет и т е р а т о р , к о т о р ы й п р о х о д и т п о м е с я ц а м г о д а ://MonthDays//месяцыclassи-определяемколичествоитератор,днейвкоторыйвозвращаетнихMonthDays{string[]{months"January"April"August30",31",30","December-это28","June"September//GetEnumeratorpublic"February"May31","November=31",и"March30",30","July"October31"31",31",31",};естьитераторSystem.Collections.IEnumeratorGetEnumerator(){foreach(stringsMonthinmonths){// Возвращаем по одномуy i e l d r e t u r n sMonth;//}месяцу в каждойНовый с и н т а к с и ситерации}А вот часть функции M a i n ( ) , где выполняется итерирование этой коллекции с применением цикла f o r e a c h :////Итерирование месяцевкаждом из нихM o n t h D a y s md// Итерируем=года,выводколичестваднейвnew M o n t h D a y s ( ) ;Console.WriteLine("Месяцы:\n");foreach(stringsMonthinmd){Console.WriteLine(sMonth);Глава 20.
Работа с коллекциями473Это исключительно простой "класс коллекции", основанный на массиве, как и клакK e y e d A r r a y . Класс содержит массив, элементы которого имеют тип s t r i n g . Ковклиент итерирует данную коллекцию, ее блок итератора выдает ему эти строки по однойКаждая строка содержит имя месяца с количеством дней в нем. Тут нет ничего сложной,Класс определяет собственный блок итератора, в данном случае как метод GetEnumerat o r ( ) . Метод G e t E n u m e r a t o r ( ) возвращает объект типа S y s t e m . C o l l e c t i o n s ,I E n u m e r a t o r . Да, вы должны были писать такой метод и ранее, но вы должны былиписать не только его, но и собственный класс-перечислитель для поддержки вашегокласса-коллекции. Теперь же вы пишете только простой метод, возвращающийпере.числитель с использованием новых ключевых слов y i e l d r e t u r n .