Г. Шилдт - С# 3.0 Полное руководство. 2010 (1160798), страница 103
Текст из файла (страница 103)
Конструирование класса МуС1авв(1пк, 1пс) Значение х: 10, значение у: 20 Вызов методов для объекта геГ1есСОЬ Сумма равна 30 Значение 14 находится между х и у В методе Зес(1пс, 1пс). Значение х: 9, значение у: 18 В методе Зес(к(онЬ1е, бочЬ1е). Значение х: 1, значение у: 23 Значение х: 1, значение у: 23 А теперь рассмотрим порядок применения рефлексии для конструирования объекта класса МуС1азз. Сначала получается перечень открытых конструкторов в следующей строке кода: Сопвсгасеог1пто[] сь = е.весСопвегассогв() Затем для наглядности примера выводятся полученные конструкторы. После этого осуществляется поиск по списку конструктора, принимающего два аргумента, как показано в приведенном ниже фрагменте кода. Гол(х От х < сь.ъепдепт хь+) ( Рагаиееег1пко(] рь = с1[к].6еерагаиесегв() т 11(р1.ъепдеь == 2) Ьгеаат ) Если такой конструктор найден, как в данном примере, то в следующем фрагменте кода получается эюемпляр объекта заданного типа: // Сконструировать объект.
оЬ)есс[] сопвагдз = пен оЬзесе[2]т сопзагдз[0] = 101 сопвагдв[1] = 201 оЬ) есе ге11есСОЬ = с1(х] . 1пчоае(сопзагдв) после вызова метода 1пноке() переменная экземпляра ге11есьбь будет ссылаться на объект типа мус1азв. А далее в программе выполняются соответствующие методы лля эюемпляра этого объекта. Следует, однако, иметь в виду, что ради простоты в данном примере предполагается наличие лишь одного конструктора с двумя аргументами типа 1пс.
Очевидно, что в реальном коде придется дополнительно проверять соответствие типов каждого параметра и аргумента. Глава 17. Динамическая идентификация топав, рефлексия и атрибуты 537 Получение типов данных из сборок В предыдущем примере все сведения о классе МуС1аяв были получены с помощью рефлексии, за исключением одного элемента: типа самого класса иус1аяя. Несмотря на то что сведения о классе получались в предыдущем примере динамически, этот пример опирался на тот факт, что имя типа муС1аяв было известно заранее и использовалось в операторе суреог для получения объекта класса туре, по отношению к которому осуществлялось косвенное или непосредственное обращение к методам рефлексии. В некоторых случаях такой подход может оказаться вполне пригодным, но истинная сила рефлексии проявляется лишь тогда, когда доступные в программе типы данных определяются динамически в результате анализа содержимого других сборок.
Как следует из главы 16, сборка несет в себе сведения о типах классов, структур и прочих элементов данных, которые в ней содержатся. Прикладной интерфейс Вейест)оп АР] позволяет загрузить сборку, извлечь сведения о ней и получить экземпляры объектов любых открыто доступных в ней типов. Используя этот механизм, программа может выявлять свою среду и использовать те функциональные возможности, которые могут оказаться доступными без явного их определения во время компиляции. Это очень эффективный и привлекательный принцип. Представьте себе, например, программу, которая выполняет роль "браузера типов", отображая типы данных, доступные в системе, или же инструментальное средство разработки, позволяющее визуально составлять программы из различных типов данных, поддерживаемых в системе.
А поскольку все сведения о типах могут быть извлечены и проверены, то ограничений на применение рефлексии практически не существует. Для получения сведений о сборке сначала необходимо создать объект класса йя яепаз1у. В классе АяяевЬ1у открытый конструктор не определяется. Вместо этого объект класса йявеи]т1у получается в результате вызова одного из его методов.
Так, для загрузки сборки по заданному ее имени служит метод аспас)рвота () . Ниже приведена его соответствующая форма. ятасхс Лввеив1у воат)кгои(ясг1пе иил файла) где имя файла обозначает конкретное имя файла сборки. Как только будет получен объект класса йяяептЫу, появится возможность обнаружить определенные в нем типы данных, вызвав для него метод бегтурея () в приведенной ниже общей форме. туре(] пектурев() Этот метод возвращает массив типов, содержащихся в сборке. Для того чтобы продемонстрировать порядок обнаружения типов в сборке, потребуются два исходных файла.
Первый файл будет содержать ряд классов, обнаруживаемых в коде из второго файла. Создадим сначала файл МуС1аявея. св, содержащий следующий код: // Файл, солержаиий три класса и носяший иия НуС1аввев.св. няяпд Буякеит с1двв НуС1авя ( 1пт. хт 1пк ут 638 часть ). Явыис() риЫ1с муС1аяв (1пс 1) ( сопво1е.ыгуяедупе("Конструирование класса МуС1авв (1пв) . ") ) х = у = 10 ЯЬон (); ) риЫ1с МуС1аяя(упи 1, 1пя 0) Сопяо1е.Иг1сеЬЯпе("'Конструирование класса МуС1авв(1пв, 1пс).
"); х = ).; у 3! ЯЬон()) риЬ11с 1пв Яим() ( гевигп х+у; ) риЫ1с Ьоо1 1вВеинееп(1пи 1) ( 11((х < 1) вй МЯ < у) ) гесигп сгие) е1яе гевигп йа1ве) ) риЫьс чо16 Вес(упв а, 1пс Ы ( Сопяо1е.ыгуие("В методе Яев(апи, 1пв). ")) х=а; Ьв ЯЬон()я ) // Перегрузить метод ЯеЫ риЫ1с чоуб Яес(боиЬ1е а, ооиЫе Ы ( Сопво1е.ыг11е("В методе Яея(йоиЫе, боиЫе) . "); х (1пс) а; у = (1пя) Ь; ЯЬом() ) ) риЬ11с чо10 ЯЬон() ( Сопяо1е.ыг1ве11пе("Значение х: (О), значение у: (1)", х, у)) ) с1авв )(повпегС1аяв ( ясг1пЯ мяЯ) риЫ1с лпоспегс1авя(всг1по ясг) ( Бво ясг( риЬ11с чо16 ЯЬон() ( Сопяо1е.Игаве11пе(няд)) Глава (7.
Динамическая идентификация типов, рефлексия и атрибуты 539 с1аяя Оево ( вкаккс нот б Ма1п() ( Сопяо1е.нтккеп1пе ("Это заполнитель. "]; ) ) Этот файл содержит класс МуС1аяя, неоднократно использовавшийся в предыдуШих примерах. кроме того, в файл добавлены второй класс Апосьекс1аяя и третий класс ь рево. Следовательно, сборка, полученная из исходного кода, находящегося в этом исходном файле, будет содержать три класса..Затем этот файл компилируется, и из него формируется исполняемый файл муС1аяяея.'ехе. Именно эта сборка и будет опрашиваться программно. Ниже приведена программа, в которой будут извлекаться сведения о файле сборки МуС1аяяея . ехе.
Ее исходный текст составляет содержимое второго файла. /* Обнаружить сборку, определить типы и создать объект с помощью рефлексии. */ пя1по Буякевт ия1по Яуясев.нек1есккопт с1аяя Нет1есСАяяевЬ1уоево ( якаС1с но1т( Мако() ( кпС на1; // Нагрузить сборку МуС1аяяея.ехе. АяяевЬ1у аяв = АяяевЬ1у.Поабусов("МуС1аяяея.ехе")т // Обнаружить типы, содержащиеся в сборке МуС1аяяея.ехе. туре[] а11сурея = аяв.пестурея()т Когеасн(туре Севр Рп а11Сурея) Сопяо1е.нгккеП1пе("Найденот " Ь Севр.иаве)т Сопяо1е.нктсеп1пе() // Использовать первый тип, в данном случае — класс МуС1аяя. Туре С = а11Сурея[0)т // использовать первый найденный класс Сопяо1е.иг1сеп1пе("Использованот " ь с.иаве)) // Получить сведения о конструкторе. Сопяктчскостпто[] с1 = С.оексопякгпскося() Сопяо1е.нгккеььпе("Доступные конструкторы: ")т когеасп(сопякгчсСостпко с 1п ск) // Вывести возвращаемый тип и имл.
сопяо1е.ик1се (" " + с.паве + "(") т // Вывести параметры. РасавеСет1пто[] рт = с.пекрагавекеся()( кок(1пс 1=0( 1 < рк.пепссьт 1ьь) ( Сопяо1е.Иг1Се(рк[1).расавекесТуре.наве + " " + р1[1].иаве)т 540 часть ). язык Са 1Е(1+1 < р1.Ьепдтп) Сопво1е.ыгзге(", ")т ) Сопяо1е.ыгкгеЬ1пе (") ") т Сопзо1е.ИтттеЬ1пе(); // Найти подходящий конструктор. гпг х; еот(х=От х < с1.ьеп9гьт х++) ( Рагащетет1пго[] р1 = с1[х].8етрагащетегв()) ЕЕ(РЕ.Ьепдтп == 2) Ьтеакт ЕЕ(х == с1.Ьепдтп) ( Сопзо1е.ыгьтеЬЕпе("Подходящий конструктор не найден."); тегпгпт е1зе Сопзо1е.ыг1теЬтпе("Найден конструктор с двумя параметрами.1п")) // Сконструировать объект.
оЬ]ест[] сопзагдв = пен оЬ]ест[2]т сопвагцв[0] = 10) сопзатОз[1) = 209 оьОесс гее1есгоь = с1[х).1пчохе(сопзатОз)т Сопзо1е.ыггтеЬЕпе("1паызов методов для объекта геЕ1есГОЬ.")) Сопзо1е.ыг1теЬЕпе()т мегьоб1пео[) щ1 = г.бегмегпок)в()т // Вызвать каждый метод. ЕогеасЬ(Метпоб1пЕо щ 1п щ1) ( // Получить параметры.
Ратащетег1пЕо[] рт = щ.бетрагащетегз() 1е(щ.наще.сощратето("Бег") =0 аа р1[0!.РагащететТуре == Гуреог(1пт)) // Это метод Яег(тпг, гпг). оЬ]ест[) агав = пен оЬ]ест[2]т агОз[0] - 9) атОз[1] = 18) щ.1пчохе(геЕ1есГОЬ, атсз)) е1зе ЕЕ(щ.ыаще.СощрагеТо("Яет")==0 аа р1[0].рагащегегтуре = гуреоЕ(г(ооь1е)) ( // Это метод Бег(бооЬ1е, бопЬ1е). оЬ]ест[] агав = пен оЬ]ест[2)т аг9я[0! = 1.12) агцз[1] = 23.4т щ.1пчоке(теЕ1есГОЬ, аг9з)т ) е1зе ) Е(щ.ыаще.СощрагеТо("Бощ") ==0) ( ча1 = (тпт) щ.1пчохе(геЕ1есГОЬ, по11) т Глава )7. Динамическая идентификация типов, рефлексии и атрибуты 541 сопяо1е.иг1сеь1пе("сумма равна " ч на1)т ) е1яе гк(и.ыаие.СоирагеТо("1яВегнееп")= О) ( оЬ3есг[] агчв = пеи оЬ)есг[ 1]; агчя[0] 144 гк((Ьоо1) и.1пносе(ге11есСОЬ, агчя)) Сопяо1е.нгггеткпе("Значение 14 находится между х и у")т ) е1яе 11(и.иаие.сожрагето("Знои")==О) ( и.1пчохе(гет1есСОЬ, пч11)) ) ) ) При выполнении этой программы получается следующий результат: Найдено; МуС1аяз Найденок АпогнегС1авя Найдено: Репо Использовано: Мус1аяя Доступные конструкторы: МуС1аяя(1пг32 г) МуС1азя(1пг32 1, 1пС32 3) Найден конструктор с двумя параметраыи.
конструирование класса мус1аяя(гпс, гпс) Значение х: 10, значение у: 20 Вызов методов для объекта гек1есСОЬ Сумма равна 30 Значение 14 находится между х и у В методе Зег(1пг, гпг). Значение х: 9, значение ук 18 В методе Нег (бочЫе, бочЫе) . Значение х: 1, значение у: 23 Значение х: 1, значение у: 23 Как следует из результата выполнения приведенной выше программы, обнаружены все три класса, содержащиеся в файле сборки МуС1аяяея. ехе. Первым среди них обнаружен класс Мус1аяя, который затем был использован для получения экземпляра объекта и вызова соответствующих методов. Отдельные типы обнаруживаются в сборке Мус1аяяея. ехе с помощью приведенной ниже последовательности кода, находящегося в самом начале метода Магп () . // Загрузить сборку муС1аяяея.ехе.
Аяяепат1у аяи = АяяезЬ1у.ьоабугои("Мус1аяяея.ехе") // Обнаружить типы, содержащиеся в сборке МуС1аяяея.ехе. Туре[) а11Сурев = аяи.оегтурея()т 642 Часть (. Язык С№ Гогеасп(туре Геир 1п а11курез) сопзо1е.иг1геьъпе("найдено: " + сеир.нане)к Этой последовательностью кода можно пользоваться всякий раз, когда требуется динамически загружать и опрашивать сборку. Однако сборка совсем не обязательно должна быть исполняемым файлом с расширением . ехе. Сборки могут быть также в файлах динамически компонуемых библиотек (ОЕЕ) с расширением .«(11.
Так, если скомпилировать исходный файл МуС1аззез.сз в следующей командной строке: сзс /г:1гЬгагу МуС1аззез. сз то в итоге получится файл мус1аззез. к)11. преимущество размещения кода в библиотеке РЕЕ заключается, в частности, в том, что в этом случае метод Магд () в исходном коде не нужен, тогда как всем исполняемым файлам требуется определенная точка входа, с которой должно начинаться выполнение программы. Именно поэтому класс Пекпо содержит метод магп () в качестве такой точки входа. А для библиотеки ОЬ). метод Ма1п () не требуется. Если же класс МуС1азз нужно превратить в библиотеку ВЬ), то в вызов метода Ьоак)утека О придется внести следующее изменение; АззезЬ1у азы АззеиЬ1у.ъоак(угои("Мус1аззеа.о11")> Полностью автоматизированное обнаружение типов Прежде чем завершить рассмотрение рефлексии, обратимся к еще одному поучительному примеру.