Нэш Трей - C# 2010. Ускоренный курс для профессионалов (2010) (1160865), страница 154
Текст из файла (страница 154)
ггу Сопво1е.Хггпеьгпе( "- б.биврзгагето( сопво1е.бис )> сагсп( Випп1вев1пбегкхсерп1оп гЬе ) ( Сопво1е.кггге) Опе( "Не удалось вывести дамп для: б.зестуре О )1 Сопво1е.кггСЕОгпе( "11" + гпе.невваие ); ) ) ) В этом примере сначала были созданы вкземпляры С и О, которые затем переданы методу ОиврбеЬио1пуо, представляющему собой оболочку вокруг Оиврзпасето. Обратите внимание, что ОиврбеЬид1пго обеспечивает утиную типизацию, принимая параметр типа бупав).
с, Также очень важно перехватывать любые исключения привяз- Динамические типы 579 ки времени выполнения, потому что, как было сказано, это большое работающее приложение включает тысячи типов, которые могут реализовывать, но могут и не реализовывать Оиарзсагето. Результат работы приведенного выше кода выглядит так: Состояние экземпляра С тса1ие == 42 Не удалось вывести дамп дпя: О 'О' с(оеа пог сопгаап а Сегтпьгьоп Тос 'Опирзтатето' (О не содержит определение Оимрзгагего) В реальной рабочей реализации может быть также включена информация. которая помогла бы точнее идентифицировать экземпляр, выводимый в дами, чтобы можно было легко найти его в отладчике.
Одним из наибольших отличий утиной типизации в СЗ с использованием с(упаатас от ее реализации в статических языках, таких как С++ с шаблонами, является то, что обнаружение ошибок типов в СЭ откладывается до момента выполнения, а в С++ они полностью обнаруживаются на этапе компиляции. На самом деле это большая разница. Утиная типизация с с(упапсас должна применяться сдержанно и тщательно для устойчивости программы. Если приходится в значительной мере полагаться на утиную типизацию с ступапсьс, не забудьте реализовать хороший механизм обработки ошибок. На протяжении всей книги неоднократно подчеркивалось, что компилятор является вашим другом, позволяя перехв тывать максимально возможное количество ошибок во время компиляции, а не во время выполнения.
Это было одним из мотивирующих факторов для реализации обобщений в Сэ 2.0. Когда используется утиная типизация с с(упади'.с, все это отбрасывается, потому должна быть готовность справиться с непредвиденными последствиями. Ограничения динамических типов Реализовать новый тип с(унана'. с не так-то легко. Есть некоторые вещи, которые просто нельзя делать с с(упапи'.с. Некоторые из них не имеют смысла, другие — имеют. но команде проектировщиков СИ, наверное, не хватило времени для их правильной реализации. Более того, как и с любым другим новым средством языка программирования, для того, чтобы узнать больше о нем и его применении, требуется время.
Другими словами, не удивляйтесь, если применение с(упади.с будет эволюционировать в течение ближайших лет. Как упоминалось ранее, использовать ступамао с расширяющими методами в СИ 4.0 нельзя. Однако в будущих версиях это может измениться. Кроме того, нельзя реализовывать динамические интерфейсы, т.е. интерфейсы, для которых в качестве одного из типов-параметров указано с(упаясас.
Также нельзя применять ступаясьс в выражениях ограничений. Динамическое создание обьектов с пОмощью ехратн$оОЬ~ ест Вплоть до этого места главы было показано, что тип ссуд апас облегчает возможность взаимодействия, и каким образом трактовать экземпляр любого типа как экаемпляр с(упапсьс. А можно ли динамически создавать типы во время выполненияу 580 Глава ) г Начиная с первой версии .)дЕТ Р'гюпевюг)с, всегда существовала возможность динамического создания кода с помощью средств из пространства имен Бузсев. Не11ессуоп. ев1с, Однако задача зто непростая. Начиная с версии .НЕТ 4.0, команда проектировщиков ОЬК предоставила тип яузсев. Оупавус. ЕхрапбоОЬдесГ, который невероятно упростил создание динамических экземпляров объектов. Рассмотрим пример; цвгпд Яузгевг цвгпд Яузсев.бупавгсг цзгпд Яузсев.Со11есс1опз.Оепег1с; зсас1с с1азз ЕппгуРо1пс ) зсасгс чогб Ма1п)) гггг Создать объект, представляющий псарню бупавгс бодКеппе1 = пен ЕхрапбоОЬ)есс()г // Установить некоторые полезные свойства с)одхеппе1.Аббгезз = "1234 ОодВопе Юау"г бодКеппе1.Стоу = "Гаггьап)сз"г бодКеппе1.ЯГасе = "А1азга"г бодКеппе1.0нпег = пен ЕхрапбоОЬ)ест))г бодКеппе1.0нпег.каве = вдгпдег"г гг/ Установить коллекцию динамических объектов собак с)одхеппе1.Оодз = пен Огзс<бупавгс>()г /гг Создать некоторые объекты собак бупав1с ГЬог = пен ЕхрапбоОЬЯесс()г ГЬог.каве = "тпог"у ГЬог.Вгееб = "Я1Ьеггап Нцз)су"Г бупав1с аро11о = пен ЕхрапбоОЬ)есг)) аро11о.каве = "Аро11о"; аро11о.Вгееб = "БРЬеггап Нцз)су"г // Поместить собак на псарню бодхеппе1.0одз.лс)с)) СЬог )) бодкеппе1.0одз.дбс)) аро11о ); ) ) Первое, что здесь бросается в глаза — после создания новый экземпляр Ехрапс)оОЬЯ ест был присвоен переменной типа с)уггав).с.
что важно, поскольку ЕхрапбоОЬ3 есс реализует интерфейс 10упав1СМегаОЬБ ессргоч1бег, от которого получает свою мощь. Обратите внимание, что свойства объекта заполнены простым присваиванием, как если бы они уже существовали. На самом деле эта операция одновременно и создает свойство, и присваивает ему значение. Вся магия осуществляется реализацией ЕхрапбоОЬдесс интерфейса 10упав1сиесаОЬя ессргоч1бег, который добавляет элемент к внутреннему словарю. Чтобы создать объекты, вложенные в объект бодкегпге1, просто присвойте новый экземпляр ЕхрапбоОЬ1есс свойству паве, как это сделано с бодКеппе1. Оыпег. Если необходимо, чтобы динамический объект содержал коллекцию объектов, просто присвойте новый экземпляр объекта-контейнера новому свойству, как это показано при присваивании экземпляра 11зс<бупав1с> свойству бодКеппе1.
Водя. Обобщенный аргумент бупавус в типе коллекции был установлен потому, что нужно, чтобы содержащиеся в коллекции объекты тоже были динамическими, которые можно создать с помощью ехрапбоОья ест. как видите, использование ехрапбоОья ест для создания экземпляров динамических объектов намного проще, чем применение Яувсев.ке11ессуоп.Евгс. Динамические типы 581 А что, если необходимо перечислить свойства динамического экземпляра, не зная их заранее? Например, как быть, если понадобится метод по имени Рг1пгехрапбоОЬ1есг для вывода на консоль содержимого любого динамического экземпляра е храп боОЬ1 е сг? сделать это легко, потому что ехратн1оОьб есг реализует интерфейс 101сг1опа гу< з гг1 од, згггпд>, благодаря которому можно перечислить свойства, содержащиеся в экземпляре Ехра ос(оОЬ1 е с Г.
Например, ниже показано, так может выглядеть одна из реализаций РггпГЕхрапбоОЬбеск: зкаГ1с чогб РггпГЕхрапбоОЬОесс( бупатгс оЬО, экггпд пате, гпс 1пбепс = 0 ) ( Гппс<1пг, згггпд> сгеагераб = (и) => ( геспгп зкгтпд . )огп ("я, ЕпптегаЫе .Кереак (" ", и) ); сапэо1е.игггеетпе( сгеагеРаб(тпбепг) + пате + ":" )) ++гпбепгт наг б1сг = (101сг1опагу<згггпд, оь)ест>) оьб) гогеасп( тсаг ргорегсу гп бгсс ) ( ге( ргореггу.ча1се гз ехрапбооьбесг ) ( // Рекурсия для вывода на консоль вложенного ЕхрапбоОЬОесг Рггпгехрапбооь)ест( ргореггу.ча1пе, ргорегсу.Кеу, гпбепг ) ) е1зе ( 11( ргореггу.ча1се гз 1епптегаЫе<бупатгс> ) ( экгбпд со11нате = ргорегсу.Кеу) Сопэо1е.нггседупе( "Коллекдия (0)(1)с", сгеасераб(гпбепс), со11ыате ); гпс гпбех 0; Гогеасп( чаг ткет гп (1ЕпптегаЫе<бупат1с>)ргорегсу.уа1ие ) згг1пд 1гетнате = зсг1пд.Гогтак( "(0)((1))", со11ыате, гпбех++ ); // Рекурсия для данного экземпляра РггпГЕхрапбоОЬОеск( гсет, 1Гетыате, гпбепк+1 )т ! ) е1зе ( Сопэо1е.нггкеьупе( "(0)(1) = (2)", сгеасераб(1пбепс), ргорегку.Кеу, ргорегсу.уа1пе )) Теперь в пример создания экземпляра с1одКеппе1 можно было бы добавить следующий код: РггпгехрапбоОьОесг( бодкеппе1, ьзгпдег'э кеппе1" )) 582 Глава 17 Обратите внимание,что каждая пара "ключ/значение" в словаре проверяется,не является ли она также другим экземпляром ЕхрапбсОЬ3есс.
Если это так, то выполняется рекурсивный вызов РгьпсЕхрапс(оОЬ3 есг, для его вывода на консоль. Аналогично, если значение является перечислимым типом, выполняется итерация по его элементам, предполагая, что все они — экземпляры ЕхрвпбсОЬ3 ест, и производится рекурсивный вызов также для них. Чтобы сделать вывод немного симпатичнее, вниз по стеку должно передаваться значение сдвига, в результате чего получится вывод вроде показанного ниже: 61пдег'в Кеппе1с Аббгевв = 1234 оодВопе Иву Сагу = РвггЬвпьв Ягвсе = А1ввКв Онпег: Наив = Озпдег Коллекция осдв: Осдв(0): Нате = Тнсг Вгееб = ЯРЬегзвп Новку Водя(1): Нвие Аро11о Вгееб = Б1Ьегавп НивКу ЭкземплярЕхрвгсбоОЬ3есгприсвоенпеременнойтипас(упвиас,анепеременнойтипа ехрвпбобь3есг.хотя его можно было присвоить и переменной типа ехрапбоОьзесг, но тогда это означало бы.что добавлять свойства к объекту можно было бы только с помошью методов, ассоциированных с интерфейсом 101сг1опагу<вгг1пд, всгьпд>.











