Г. Шилдт - С#4.0 Полное руководство (1160795), страница 109
Текст из файла (страница 109)
Если идентификатор определен, то метод выполняется, когда он вызывается. Если же идентификатор не определен, то метод не выполняется. Оба метода, Тгфа1 () и Ке1еазе (), вызываются в методе Мафп () . Но поскольку определен один лишь идентификатор ТК1АЬ, то выполняется только метод Тгфа1 (), тогда как метод Ке1еазе () игнорируется. Если же определить идентификатор КЕЬЕАБЕ, то метод Ке1еазе () будет также выполняться. А если удалить определение идентификатора ТК1А1,, то метод Тгфа1 () выполняться не будет.
Атрибут Сопб1сфопа1 можно также применить в классе атрибута, т.е. в классе, наследующем от класса АССг1Ьпбе. Так, если идентификатор определен, то атрибут применяется, когда он встречается в ходе компиляции. В противном случае он не применяется. На условные мез оды накладывается ряд ограничений. Во-первых, они должны возвращать значение типа чо1с(, а по существу, ничего не возвращать.
Во-вторых, они должны быть членами класса или структуры, а не интерфейса. И в-третьих, они не могут предшествовать ключевому слову очеггзс(е. Атрибут ОЬво1е1е Атрибут Оьзо1есе (сокращенное наименование класса еузсеы. Оьзо1есеАссгзьпсе) позволяет пометить элемент программы как устаревший. Ниже приведена общая форма этого атрибута: (ОЬзо1ете ("сообыение") ) Глава 1?. Динамическав идентификация типов, рефлексия и атрибуты 573 где сообщение выводится при компилировании элемента программы, помеченного как устаревший.
Ниже приведен краткий пример применения данного атрибута. продемонстрировать применение атрибута оьяо1есе. оя1пд Зуягешч с1аяя Теяс ( (ОЬяо1ете("Лучше испольэовать метод МунеСЬ2.")] роь11с япая1с тпп МумеСЬ(ьпо а, ьпя Ы ( гесогп а / Ь; ) // усовершенствованный вариант метода мумесь. риыьс ясастс 1пс мумесь2(1пс а, тпс ы ( гепогп Ь == О 2 О : а /Ьч ) япая1с чоьб Маьп() ( /) Ллл этого кода выводится предупреждение. Сопяо1е.Хгтоез ьпе("4 / 3 равно " + Теяюнунеяь(4, 3)) А для этого кода предудреждеиие ие выводится. Сопяо1е.Хгьоевьпе("4 / 3 равно " + Теяю МУМеСЬ2(4, 3)); Когда по ходу компиляции программы в методе Мадп () встречается вызов метода МунеСЬ (), формируется предупреждение, уведомляющее пользователя о том, что ему лучше воспользоваться методом МуиеСЬ2 () .
Ниже приведена вторая форма атрибута оьяо1есе: (ОЬяо1еае("сообщение", ошибка)] где ошибка обозначает логическое значение. Если это значение истинно (с где), то при использовании устаревшего элемента формируется сообщение об ошибке компиляции вместо предупреждения.
Зта форма отличается тем, что программа, содержащая подобную ошибку, не будет скомпилирована в исполняемом виде. 576 Часть Е Язык С№ В этой главе описываются синтаксис, теория и практика применения обобщений, а также показывается, каким образом обобщения обеспечивают типовую безопасность в ряде случаев, которые раньше считались сложными. После прочтения настоящей главы у вас невольно возникнет желание ознакомиться с материалом главы 25, посвященной коллекциям, так как в ней приведено немало примеров применения обобщений в классах обобщенных коллекций. Что такое обобщения Термин обобщение, по существу, означает параметризирооаннаи тип.
Особая роль параметризированных типов состоит в том, что они позволяют создавать классы, структуры, интерфейсы, методы и делегаты, в которых обрабатываемые данные указываются в виде параметра. С помощью обобщений можно, например, создать единый класс, который автоматически становится пригодным для обработки разнотипных данных. Класс, структура, интерфейс, метод или делегат, оперирующий параметризированным типом данных, называется обобщенным, как, например, обобщенный класс или обобщенный метод.
Следует особо подчеркнуть, что в СФ всегда имелась возможность создавать обобщенный код, оперируя ссылками типа оЬб есг. А поскольку класс оЬб есг является базовым для всех остальных классов, то по ссылке типа оЬз ест можно обращаться к объекту любого типа. Таким образом, до появления обобщений для оперирования разнотипными объектами в программах служил обобщенный код, в котором для этой цели использовались ссылки типа оЬб есг. Но дело в том, что в таком коде трудно было соблюсти типовую безопасность, поскольку для преобразования типа оЬ2 ее с в конкретный тип данных требовалось приведение типов. А это служило потенциальным источником ошибок из-за того, что приведение типов могло быть неумышленно выполнено неверно.
Это затруднение позволяют преодолеть обобщения, обеспечивая типовую безопасность, которой раньше так недоставало. Кроме того, обобщения упрощают весь процесс, поскольку исключают необходимость выполнять приведение типов для преобразования объекта или другого типа обрабатываемых данных. Таким образом, обобщения расширяют возможности повторного использования кода и позволяют делать это надежно и просто.
ПРИМЕЧАНИЕ Программирующим на С++ и дача необходимо иметь в виду, что обобщения в С№ не следует путать с шаблонами в С++ и обобщениями в дача, поскольку это разные, хотя и похожие средства. В действительности между этими тремя подходами к реализации обобщений существуют коренные различия.
Если вы имеете некоторый опыт программирования на С++ или дача, то постарайтесь на основании этого опыта не делать никаких далеко идущих выводов о том, как обобщения действуют в С№. Простой пример обобщений Начнем рассмотрение обобщений с простого примера обобщенного класса.
В приведенной ниже программе определяются два класса. Первым из них является обобщенный класс Сеп, вторым — класс Сепегдсзоето, в котором используется класс Сеп. Глава 18. Обобщения 577 // Простой пример обобщенного класса. патио Бувсеш; // В приведенном ниже классе Оеп параметр типа Т заменяется // реальным типом данных при создании объекта типа Оеп. с1азв Оеп<т> ( т оЬ; // объявить переменную типа Т // Обратите внимание на то, что у этого конструктора имеется параметр типа Т. рпЬ11с Оеп(Т о) ( оЬ = о; ) // Возвратить переменную экземпляра оЬ, которая относится к типу Т. рпЬ11с т ОетОЬ() ( гегпгп оЬ; ) Показать тип Т. рпЬ11с тога БЬонтуре() ( Сопво1е.Хг1септпе(ЩХ типу Т относится " + Суреоу(Т))( ) ) // Продемонстрировать применение обобщенного класса.
с1авв Оепег1свпешо ( впаптс чотб Мати() ( // Создать переменную ссылки на объект Оеп типа тпс. Оеп<тпс> ТОЬ( // Создать объект типа Оеп<тпс> и присвоить ссылку на него переменной ТОЬ. 1ОЬ = пеы Пеп<тпт>(102)] Показать тип данных, хранящихся в переменной ТОЬ. 1ОЬ.БЬоиТуре(); // Получить значение переменной ТОЬ. 1пб ч = 1ОЬ.ОеСОЬ()( Сопво1е.нг1теьтпе("Значение: " + ч)( Сопзо1е.нг1севтпе()( // Создать объект типа Пеп для строк. Оеп<зтгтпо> зтгОЬ = пеи Яеп<втгтпо>("Обобщения повышают эффективность."]] // Показать тип данных, хранящихся в переменной впгОЬ. втгОЬ.БЬоитуре(); // Получить значение переменной вггОЬ.
втггпс впг = зггОЬ.ПесОЬ(); сопво1е.хгтсеьтпе("значение: " + всг)( ) ) 578 Часть!. Язык С() Эта программа дает следующий результат. К типу Т относится Зуввеш.1пв32 Значение: 102 К типу Т относится Зуввеш.зтг1пэ Значение: Обобшения повышают эффективность. Внимательно проанализируем эту программу. Прежде всего обратите внимание на объявление класса Оеп в приведенной ниже строке кода: с1авв Оеп<Т> ( где Т вЂ” это имя парамегпра типа. Это имя служит в качестве метки-заполнителя конкретного типа, который указывается при создании объекта класса Оеп.
Следовательно, имя Т используется в классе Оеп всякий раз, когда требуется параметр типа. Обратите внимание на то, что имя Т заключается в угловые скобки (< >). Этот синтаксис можно обобщить: всякий раз, когда объявляется параметр типа, он указывается в угловых скобках. А поскольку параметр типа используется в классе Оеп, то такой класс считается обоби(енным. В объявлении класса Оеп можно указывать любое имя параметра типа, но по традиции выбирается имя Т. К числу других наиболее употребительных имен параметров типа относятся у и е.
Вы, конечно, вольны использовать и более описательные имена, например Туа1пе или Ткну. Но в этом случае первой в имени параметра типа принято указывать прописную букву Т. Далее имя Т используется для объявления переменной оЬ, как показано в следующей строке кода. Т оЬг // объявить переменную типа Т Как пояснялось выше, имя параметра типа Т служит меткой-заполнителем конкретного типа, указываемого при создании обьекта класса Оеп.
Поэтому переменная оЬ будет иметь тип, привязываемый к Т при получении экземпляра объекта класса Оеп. Так, если вместо т указывается тип в Ь гхпо, то в экземпляре данного объекта переменная оЬ будет иметь тип всг1пд. А теперь рассмотрим конструктор класса Оеп. роЬ11с Оеп(Т о) ( оЬ = о; ) Как видите, параметр о этого конструктора относится к типу Т. Это означает, что конкретный тип параметра о определяется типом, привязываемым к Т при создании объекта класса Оеп. А поскольку параметр о и переменная экземпляра оЬ относятся к типу Т, то после создания объекта класса Оеп их конкретный тип окажется одним и тем же.