Г. Шилдт - С# 3.0 Полное руководство. 2010 (1160798), страница 106
Текст из файла (страница 106)
Встроенные атрибуты В языке С() предусмотрено несколько встроенных атрибутов, но три из них имеют особое значение, поскольку они применяются в самых разных ситуациях. Это атрибуты Аггг1Ьцтепзаде, Сопбфтгопа1 и ОЬзо1есе, рассматриваемые далее по порядку. Глава )7, Динамическая идентификация типов, рефлексия и атрибуты 553 Атрибут Ай~~~Ьийео заде АССгаЬигеияаде (АССг1Ьикетагдекв элемент) где элемент обозначает один или несколько элементов, к которым может быть применен объявляемый атрибут, тогда как АССг1Ьигетагдегв — перечисление, в котором опреде- ляются приведенные ниже значения.
й11 АввевЬ1у Явив гпгегкасе РгорегСу С1авв Япеиг МеСЛоб аекигпиа1ие Сопвкгисгог Рсетб Моии1е Ясгист. Ре1еиаге Пепегасрагамекег Рагап|егег Два этих значения или более можно объединить с помощью логической операции ИЛИ. Например, для указания атрибута, применяемого только к полям и свойствам, используются следующие значения: АССгсиикетагсегв.г1е1и ) АССгсъигетагиекв.ргореггу В классе атрибута Ассг1Ьисецваие поддерживаются два именованных параметра. Первым из них является параметр А11омми1СТр1е, принимающий логическое значение.
Если это значение истинно, то атрибут может быть применен к одному и тому же элементу неоднократно. Второй именованный параметр, 1ппегъгеб, также принимает логическое значение. Если это значение истинно, то атрибут наследуется производными классами, а иначе он не наследуется. По умолчанию параметр А11омми1СТР1е принимает ложное значение (г а1ве), а параметр 1ппег1 Себ — истинное значение (Сгие). В классе атрибута АССг1ЬигецяаЯе определяется также доступное только для чтения свойство иа1160п.
Оно возвращает значение типа АССг1Ьигетагдегя, определяющее типы элементов, к которым можно применять объявляемый атрибут. По умолчанию используется значение АССгТЬигетагиегя. А11. Атрибут СотаЖЫ.оаа1 Атрибут сопб1с1опа1 представляет, вероятно, наибольший интерес среди всех встроенных атрибутов. Ведь он позволяет создавать условные методы, которые вызываются только в том случае, если с помощью директивы ))с)ебспе определен конкретный идентификатор, а иначе метод пропускается. Следовательно, условный метод служит альтернативой условной компиляции по директиве ))11. Сопс)1Ссопа1 — это, по существу, еще одно наименование класса яуягетп. Р1аипояС1ся.
Сопс)1С1опа1АССг1ЬиСе. Для применения атрибута Сопбугъопа1 в исходный код программы следует включить пространство имен Яуякем. Р1адпоякъсв. Рассмотрим применение данного атрибута на следующем примере программы. // Продемонстрировать применение встроенного атрибута Соиисксопа1. Ебесспе тптАЪ Как упоминалось ранее, атрибут АССг1Ьигепяаде определяет типы элементов, к которым может быть применен объявляемый атрибут. Ассг1Ьисепваие — это, по существу, еще одно наименование класса Яуягем.
АССг1ЬигепвадеАССг1Ьиге. У него имеется следующий конструктор: 554 Часть ). Язык Е» изгпд Яузсев; изгое Яузсев. Пгадпозг1сз; с1азз Тезг ( (Сопбгг1опа1("ТП1А1") ) чо1б Тгга1() ( Сопзо1е.иг1сепгпе("Пробная версия, не " + "предназначенная для распространения."); ) (Сопб1С1опа1("НЕЬЕАЯЕ")) чо1б Пе1еазе П ( Сопзо1е.иггсеЬгпе("Окончательная рабочая версия."); ) зсасгс чогб магд() ( твзс с = пеы тезс() С.Тгга1(); //вызывается только в том случае, если // определен идентификатор ТП1АЬ С.ке1еазе О; // вызывается только в том случае, если // определен идентификатор КЕЬЕАЯЕ Эта программа данг следующий результат: Пробная версия, не предназначенная для распространения.
Рассмотрим эту программу подробнее, чтобы стал понятнее результат ее выполнения. Прежде всего обратите внимание на то, что в этой программе определяется идентификатор ТЕ1АЬ. Затем обратите внимание на определение методов Тгфа1 () и Ее1еазе () . Каждому из них предшествует атрибут Сопб1гфопа1, общая форма которого приведена ниже.
(Сопбгг1опа1 идентификатор! где идентификатор обозначает конкретный идентификатор, определяющий условие выполнение метода. Данный атрибут может применяться только к методам. Если идентификатор определен, то метод выполняется, когда он вызывается. Если же идентификатор не определен, то метод не выполняется. Оба метода, Тгфа1 () и Ее1еазе (), вызываются в методе иафп () .
Но поскольку определен один лишь идентификатор ТЕХАЬ, то выполняется только метод Тг1а1 (), тогда как метод Ее1еазе () игнорируется. Если же определить идентификатор ЕЕЬЕАЯЕ, то метод Ее1еазе () будет также выполняться. А если удалить определение идентификатора тп1Аь, то метод тгз.а1 ( ) выполняться не будет. На условные методы накладывается ряд ограничений. Во-первых, они должны возвращать значение типа чсфср, а по существу, ничего не возвращать. Во-вторых, они должны быть членами класса или структуры, а не интерфейса. И в-третьих, они не могут предшествовать ключевому слову очегг1бе. Атрибут ОЬэо1е йе Атрибут ОЬз о1е Се (сокращенное наименование класса Я уз Сев. ОЬзо1егелгггЬЬпге) позволяет пометить элемент программы как устаревший.
Ниже приведена общая форма этого атрибута. (Опзо1еге("сообщение")) Глава )7. Динамическая идентификация типов, рефлексия и атрибуты 555 где сообщение выводится при компилироваиии элемента программы, помеченного как устаревший. Ниже приведен краткий пример применения данного атрибута. // Продемонстрировать применение атрибуте ОЬво1есе. ов1по Бувсешт с1авв тевк ( [Опво1еке("Лучше испольэовать метод МумеКЬ2.")) рпЬ11с вкак1с апк Мумекп(1пк а, апк Ь) ( гекигп а / Ь) ) // Усовершенствованный вариант метода Мумепп. ров11с вкакас 1пк МумеСЬ2(апк а, 1пк Ь) ( гекнтп Ь == О ? О : а /Ьт вкакгс жо1О Ма1п() ( // для этого кода выводится предупреждение. Сопво1е.икакетапе( "4 / 3 равно " + Тевк.муиекп(4, 3))т // А для этого кода предупреждение не выводится. Сопво1е.иг1пе11пе( "4 / 3 равно " + тевс.иуметп2(4, 3))т Когда по ходу компиляции программы в методе Маап () встречается вызов метода мумесЬ(), формируется предупреждение, уведомляющее пользователя о том, что ему лучше воспользоваться методом мумесЬ2 ( ) .
Ниже приведена вторая форма атрибута Оьэо1ете. [Оьво1есе("сообщение", ошибка)] где ошибка обозначает логическое значение. Если это значение истинно (скпе), то при использовании устаревшего элемента формируется сообщение об ошибке компиляции вместо предупреждения. Эта форма отличается тем, что программа, содержащая подобную ошибку, ие будет скомпилироваиа в исполняемом виде. ГЛАВА Обобщения та глава посвящена обобщениям — одному из самых сложных и эффективных средств С№.
Любопытно, что обобщения не вошли в первоначальную версию 1.0 и появились лишь в версии 2.0, но теперь они являются неотъемлемой частью языка С№. Не будет преувеличением сказать, что внедрение обобщений коренным образом изменило характер С№. Это нововведение не только означало появление нового элемента синтаксиса данного языка, но и открыло новые возможности для внесения многочисленных изменений и обновлений в библиотеку классов.
И хотя после внедрения обобщений прошло уже несколько лет, последствия этого важного шага до сих пор сказываются на развитии С№ как языка программирования. Обобщения как языковое средство очень важны потому, что они позволяют создавать классы, структуры, интерфейсы, методы и делегаты для обработки разнотипных данных с соблюдением типовой безопасности. Как вам должно быть известно, многие алгоритмы очень похожи по своей логике независимо от типа данных, к которым они применяются. Например, механизм, поддерживающий очередь, остается одинаковым независимо от того, предназначена ли очередь для хранения элементов типа йпс, зсг1по, оГг1есс или для класса, определяемого пользователем.
До появления обобщений для обработки данных разных типов приходилось создавать различные варианты одного и того же алгоритма. А благодаря обобщениям можно сначала выработать единое решение независимо от конкретного типа данных, а затем применить его к обработке данных самых разных типов без каких-либо дополнительных усилий.
В этой главе описываются синтаксис, теория и практика применения обобщений, а также показывается, каким образом обобщения обеспечивают типовую безопасность в ряде случаев, которые раньше считались тяжелыми. После прочтения настоящей главы у вас невольно возникнег желание ознакомиться с материалом главы 24, посвященной коллекциям, так как в ней приведено немало примеров применения обобщений в классзх обобщенных коллекций. Что такое обобщения Термин обобщение, по существу, означает параметрпзированный тип. Особая роль парамстризированных типов состоит в том, что они позволяют создавать классы, структуры, интерфейсы, методы и делегаты, в которых обрабатываемые данные указываются 588 часть!, язык сз в виде параметра. С помощью обобщений можно, например, создать единый класс, который автоматически становится пригодным для обработки разнотипных данных.
Класс, структура, интерфейс, метод или делегат, оперирующий параметризированным типом данных, называется обобщенным, как, например, обобщенный класс или обобщенный метод. Следует особо подчеркнуть, что в С(( всегда имелась возможность создавать обобщенный код, оперируя ссылками типа оьзесс. А поскольку класс оьбесс является базовым для всех остальных классов, то по ссылке типа пыл ест можно обращаться к объекту любого типа.
Таким образом, до появления обобщений для оперирования разнотипными объектами в программах служил обобщенный код, в котором для этой цели использовались ссылки типа ОЬз ест. Но дело в том, что в таком коде трудно было соблюсти типовую безопасность, поскольку для преобразования типа ОЬз ест в конкретный тип данных требовалось приведение типов. А это служило потенциальным источником ошибок из-за того, что приведение типов могло быть неумышленно выполнено неверно.
Это затруднение позволяют преодолеть обобщения, обеспечивая типовую безопасность, которой раньше так недоставало. Кроме того, обобщения упрощают весь процесс, поскольку исключают необходимость выполнять приведение типов для преобразования объекта или другого типа обрабатываемых данных. Таким образом, обобщения расширяют возможности повторного использования кода и позволяют делать это надежно и просто. гга заметку! Программирующим на С++ и./апа сгвдувт иметь в вигл/, что обобщения в Ся не нужно путать с шаблонами в С++ и обобщениями власа, так как это разные, хотя и лохожив средства. В действительности между этими тремя подходами к реализации обобщений существуют корвниыв различия. Если вы имеете некоторый опыт программирования на С++ или Зава, то постарайтесь на основании этого опыта не делать никаких далеко идущих выводов о том, как обобщения действуют в Сл.
Простой пример обобщений Начнем рассмотрение обобщений с простого примера обобщенного класса. В приведенной ниже программе определяются два класса. Первым из них является обобщенный класс Оеп, вторым — класс ОепегйсэВещо, в котором используется класс Оеп. // Простой пример обобщенного класса. пэтпд зуэсевп // В приведенном ниже классе Оеп параметр типа Т // заменяется реальным типом данных при создании // объекта типа Оеп. с1авв цеп<Т> ( Т оЬ) // объявить переменную типа Т // Обратите внимание на то, что у этого конструктора // имеется параметр типа Т.
рпЬТГс Оеп(Т о) ( оЬ = ог // Возвратить переменную экземпляра оЬ, которая относится к типу Т. Глава 18. Обобщения 559 рпбттс Т ЯеСОЬ() ( гегогп оЬл ) // Показать тип т. роЬ11с чотб ЯпонТуре П ( Сопзо1е.нг1гесапе("К типу Т относится " + Суреот(т))л ) ) // Продемонстрировать применение обобщенного класса.