Г. Шилдт - С#4.0 Полное руководство (1160795), страница 137
Текст из файла (страница 137)
рагг1а1 чо1о Яном(); ) рагвга1 с1аяя ХХ роЬ11с гпс Х ( Пес; яес; ) // Реализовать частичный метод. рагсьа1 чо1с) БЬон() ( Сопяо1е.яг1серяпе("(О), (1)", Х, Х); ) ) рагг1а1 с1аяя ХХ ( рпЫгс гпс Х ( дес; яес; // Вызвать частичный метод. рсЫ1с чо1с БьонХХ() Бьон () ~ ) ) с1аяя Теяг ( яоав1с чогс) Иагп() ( ХХ ху = п ХХ(1, г); ху.зьонХУ(); Обратите внимание на то, что метод БЬоы () объявляется в одной части класса ХХ, а реализуется в другой его части. В реализации этого метода выводятся значения координат Х и У. Это означает, что когда метод яьоы () вызывается из метода ЯЬонХХ (), то данный вызов действительно имеет конкретные последствия: вывод значений Глава 20. Небезопасный код, указатели, обнуляемые типы в разные ключевые слова 703 координат Х и У. Но если закомментировать реализацикз метода П Лом (), то его вызов из метода ЯЬоиху () ни к чему не приведет. Частичным методам присущ ряд следующих ограничений.
Они должны возвращать значение типа чолб. У них не может быть модификаторов доступа и они не могут быть виртуальными. В них нельзя также использовать параметры опт. Создание объектов динамического типа Как уже упоминалось не раз, начиная с главы 3, С() является строго типизированным языком программирования. Вообще говоря, это означает, что все операции проверяются во время компиляции на соответствие типов, и поэтому действия, не поддерживаемые конкретным типом, не подлежат компиляции.
И хотя строгий контроль типов дает немало преимуществ программирующему, помогая создавать устойчивые и надежные программы, он может вызвать определенные осложнения в тех случаях, когда тип объекта остается неизвестным вплоть до времени выполнения. Нечто подобное может произойти при использовании рефлексии, доступе к СОМ-объекту или же в том случае, если требуется возможность взаимодействия с таким динамическим языком, как, например, (гопру()топ.
До появления версии С() 4.0 подобные ситуации были трудноразрешимы. Поэтому для выхода из столь затруднительного положения в версии О) 4.0 был внедртн новый тип данных под названием бупащьс. За одним важным исключением, тип бупащлс очень похож на тип оЬ0 есс, поскольку его можно использовать для ссылки на объект любого типа. А отличается он от типа оЬ) есг тем, что вся проверка объектов типа бупат1с на соответствие типов откладывает до времени выполнения, тогда как объекты типа оЬз есг подлежат этой проверке во время компиляции. Преимущество откладывания подобной проверки до времени выполнения состоит в том, что во время компиляции предполагается, что объект типа бупатлс поддерживает любые операции, включая применение операторов, вызовы методов, доступ к полям и т.д.
Это дает возможность скомпилировать код без ошибок. Конечно, если во время выполнения фактический тип, присваиваемый объекту, не поддерживает ту или иную операцию, то возникнет исключительная ситуация во время выполнения. В приведенном ниже примере программы применение типа с(упащ1с демонстрируется на практике. Продемонстрировать применение типа бупащтс. пя1пп Зуясещ; ия1пд Яуясещ.01оЬа11яас1оп; с1аяя Пупоеяю ( ясасьс чоьб Маьп () ( // Объявить дяе динамические переменные. бупащ1с яьт1 бупащьс ча1; Поддерживается неявное преобразование я динамические типы. // Поэтому следующие присваивания вполне допустимы. яст = "Это строка"; ча1 = 10; 704 Часть (.
Язык С() сопяо1е.хгггеьгпе("переменная ягг содеряяят: " + ягг); сопяо1е .хг1геььпе ("переменная ча1 содержит: " + ча1 + ' 1п'); *Гг = япг. Топррег (Со1соге1пто. Соггепссо1соге); сопяо1е.хггсеььпе("переменная ягг теперь содержит: " + ягг) ча1 = ча1 + 2; Сопво1е.Хг1сеьгпе("Переменная ча1 теперь содержит: " т ча1 + '1п')1 ясгтпэ Ясг2 = ягг.тоЬонег(со1Гнге1пго.снггепссо1спге); Сопяо1е.Хггсеьтпе("Переменная ясг2 содержит: " + *Гг2); неявные преобразования из динамических типов.
// Поддерживаются гпс х = ча1 * 2; Сопяо1е.иггсеьтпе (" Переменная х содерзит: " т к); Выполнение этой программы дает следующий результат. Переменная ясг содержит: Это строка Переменная ча1 содержит: 10 Переменная ясг теперь содержит: ЭТО СТРОКА Переменная ча1 теперь содержит: 12 Переменная ягг2 содержит: зто строка Переменная х содержит: 24 Обратите внимание в этой программе на две переменные ягг и ча1, объявляемые с помощью типа с(упатЬс. Это означает, что проверка на соответствие типов операций с участием обеих переменных не будет произведена во время компиляции.
В итоге для них оказывается пригодной любая операция. В данном случае для переменной ябг вызываются методы Топррег () и ТОЬохег () класса ятггпоь а переменная участвует в операциях сложения и умножения. И хотя все перечисленные выше действия совместимы с типами объектов, присваиваемых обеим переменным в рассматриваемом здесь примере, компилятору об этом ничего не известно — он просто принимает.
И это, конечно, упрощает программирование динамических процедур, хотя и допускает возможность'(тоявления ошибок в подобных действиях во время выполнения. В разбираемом здесь примере программа ведет себя "правильно" во время выполнения, поскольку объекты, присваиваемые упомянутым выше переменным, поддерживают действия, выполняемые в программе. В частности, переменной ча1 присваивается целое значение, и поэтому она поддерживает такие целочисленные операции, как сложение. А переменной ясг присваивается символьная строка, и поэтому она поддерживает строковые операции. Следует, однако, иметь в виду, что ответственность за фактическую поддержку типом объекта, на который делается ссылка, всех операций над данными типа с(упат1с возлагается на самого программирующего.
В противном случае выполнение программы завершится аварийным сбоем. В приведенном выше примере обращает на себя внимание еще одно обстоятельство: переменной типа бупаю1с может быть присвоен любой тип ссылки на объект благодаря неявному преобразованию любого типа в тип с(упаю1с. Кроме того, тип г(упаю1с автоматически преобразуется в любой другой тип. Разумеется, если во время выполнения такое преобразование окажется неправильным, то произойдет ошибка Глэва 20. Небезопасный код, указатели, обнуляемые типы и разные ключевые слова 705 при выполнении. Так, если добавить в конце рассматриваемой здесь программы следующую строку кода: Ьсс1 Ь = яя1; то возникнет ошибка при выполнении из-за отсутствия неявного преобразования типа 1пе (который оказывается типом переменной уа1 во время выполнения) в тип Ьоо1.
Поэтому данная строка кода приведет к ошибке при выполнении, хотя она и будет скомпилирована безошибочно. Прежде чем оставить данный пример программы, попробуйте поэкспериментировать с ней. В частности, измените тип переменных ягг и ча1 на оЬбесц а затем попытайтесь скомпилировать программу еще раз. В итоге появятся ошибки при компиляции, поскольку тип оЬ) есе не поддерживает действия, выполняемые над обеими переменными, что и будет обнаружено во время компиляции.
В этом, собственно, и заключается основное отличие типов оЬ)есг и с)упаы1с. Несмотря на то что оба типа могуг использоваться для ссылки на объект любого другого типа, над переменной типа оЬ) есе можно производить только те действия, которые поддерживаются типом сЬ1 есм Если же вы используете тип с)упаяя1с, то можете указать какое угодно действие, при условии что это действие поддерживается конкретным объектом, на который делается ссылка во время выполнения. Для того чтобы стало понятно, насколько тип с)упаы1с способеи упростить решение некоторых задач, рассмотрим простой пример его применения вместе с рефлексией. Как пояснялось в главе 17, чтобы вызвать метод для объекта класса, получаемого во время выполнения с помощью рефлексии, можно, в частности, обратиться к методу 1пчоке () .
И хотя такой способ оказывается вполне работоспособным, нужный метод намного удобнее вызвать по имени в тех случаях, когда его имя известно. Например, вполне возможна такая ситуация, когда в некоторой сборке содержится конкретный класс, поддерживающий методьв имена и действия которых заранее известны. Но поскольку эта сборка подвержена изменениям, то приходится постоянно убеждаться в том, что используется последняя ее версия.
Для проверки текущей версии сборки можно, например, воспользоваться рефлексией, сконструировать объект искомого класса, а затем вызвать методы, определенные в этом классе. Теперь эти методы можно вызвать по имени с помощью типа с) упаы1с, а не метода 1пчо)се ( ), поскольку их.имена известны. Разместите сначала приведенный ниже код в файле с именем МуС1аяя . ся. Этот код будет динамически загружаться посредством рефлексии. риЬ11с с1аяя ОьяВу ( рсв11с Ъсс1 1яоятВу(ьпя а, 1пя Ы ( 11((а а Ы == 0) геяигп яссе; геяпгп га1яе; ) рпЬ11с Ьсс1 1якчеп(ьпя а) ( 11((а Ъ 2) == О) геспгп ггие; геясгп Га1яе; ) ) Затем скомпилируйте этот файл в библиотеку РЕЕ под именем МуС1аяя. с)11. Если вы пользуетесь компилятором командной строки, введите в командной строке следующее. сяс /Ю11ьгагу Иус1аяя, са 706 Часть!.
Язык С№ Далее составьте программу, в которой применяется библиотека муС1а я я . б11, как показано ниже. О Использовать тип бупаю1с вместе с рефлексией. цягп9 Яуясею; сягпс Яуягею.не11ессгоп/ с1аяя Оупаегбеюо ( ягаггс чо1б магп() ( Ляяеюогу аяю = АяяеюЬ1У.Ьоабугою("МУС1аяя.б11")) Туре(! а11 = аяю.оестурея(); // Найти класс ОгчВу.
гпг г; гог(1 = О," 1 < а11.Ьеп9ГЬ; 1++) 11(а11(1].маме == "О1чВУ") Ъгеаьи 11(1 == а11.ЬепВГЬ) ( Сопяо1е.игггеьгпе("Класс Огчау не найцен в сборке."); ГЕГЦГП/ ) туре с = а11[г]/ // )( теперь найти используемый по умолчанию конструктор. сопяггцссог1пто(] сг = г .Оегсопясгцссогя () 1 1пс 3; Тот(3 = О; 3 < сг.т.епдГЬ; 3-н.) 11(с1[3].оесрагаюесегя().ЬепОГЬ == О) Ьгеаьп га(3 == с1.Ьеп9ГЬ) ( Сопяо1е.нггсеЬгпе("Используемый по умолчанию конструктор не найден."); гегигп; // Создать объект класса О1УВу динамически. бупаюгс оЬ3 = с1[3].1пчоке(пц11)/ // Далее вызвать по имени методы для переменной оЬ]. Это вполне допустимо, поскольку переменная оЬ3 относится к типу бупаюгс, а вызовы методов // проверяются на соответствие типов во время выполнения, а не компиляции. 11(оЬ3.1вбгчеу(15, 3)) Сопяо1е.игггеьбпе("15 делится нацело на 3.") 1 е1яе сопяо1е.хггсеььпе("15 не делится нацело на 3."); 1Т(оЬ3.1вкчеп(9)) Сопяо1е.нггтеьфпе("9 четное число."); е1яе Сопяо1е.нг1геьгпе("9 ЙЕ четное число."); ) ) Глава 20.