Вторник, 21.11.2017, 12:59
Приветствую Вас Гость | RSS

Лекции

Меню сайта
Форма входа
Категории раздела
ТАУ (Теория автоматического управления) [31]
лекции по ТАУ
Экология [151]
учебник
Бухгалтерский учет и налогообложение в строительстве [56]
Дементьев А.Ю. - Практическое пособие
Психология [104]
Пип
информатика [80]
с# Карли Ватсон
современные стулья [0]
новинки
Поиск
Главная » 2010 » Февраль » 11 » Атрибуты
00:47
Атрибуты
Атрибуты
В этой главе будет рассказано о том, что такое атрибуты и для чего они могут
быть использованы, а в качестве примера будут приведены некоторые атрибуты,
используемые в .NET Framework.
Будет также обсуждено понятие нестандартных атрибутов — атрибутов, кото-
рые вы можете создавать самостоятельно для расширения вашей системы, и при-
ведено несколько работающих примеров. Будет рассмотрен вопрос о том, каким
образом Intermediate Language Disassembler (iidasm — дисассемблер промежу-
точного языка) может использоваться для обнаружения атрибутов существующих
модулей.
Атрибуты являются одной из наиболее полезных особенностей .NET Framework.
Они часто используются компанией Microsoft. Для того чтобы научиться эффек-
тивно их использовать, придется потратить значительное количество времени, но
оно того стоит. В последующих разделах мы познакомимся с тем, каким образом
атрибуты могут применяться в следующих областях:
• Отладка
• Обеспечение информацией о модулях
• Обозначение' методов и классов как устаревших
• Условная компиляция
• Доступ к базам данных
В этой главе будет подробно рассказано о том, как создавать собственные ат-
рибуты, расширяющие возможности системы, и продемонстрировано несколько
работающих примеров нестандартных атрибутов. Прочитав главу, вы получите до-
статочно знаний о том, что из себя представляют атрибуты и каким образом их
можно использовать в своих проектах.
Что такое атрибут?
Дать атрибуту определение, состоящее из одного предложения, довольно сложно;
изучать атрибуты лучше всего на примере их использования. На данном этапе мы
определим атрибут как некоторую дополнительную информацию, которая может
относится к отдельным участкам кода в рамках одного модуля, таким как класс,
метод или свойство. Эта информация является доступной для любого другого класса,
который обращается к данному модулю.
614 Глава 22
Solution 'Assemblylnfo* (1 project)
Й- jjp Assemblylnfo
Щг Ш References
I FormLcs
В предшествующей главе мы обсуждали понятие модулей
И уПОМИНаЛИ фаЙЛ Assemblylnfo.cs. Для ТОГО ЧТОбЫ раССМОТ-
реть этот файл, следует создать в VS новый проект и открыть
Solution Explorer (Ctrl+Alt+L). Вы увидите нечто похожее на
изображенное на рисунке слева.
Если два раза щелкнуть мышью на этом файле, можно
увидеть код, который был создан VS. Часть этого кода приво-
дится ниже:
using System.Reflection;
using System.Runtime.CompilerServic.es;
Атрибут
//Общая информация о модуле контролируется посредством
// следующего набора атрибутов. Для того чтобы внести
/У изменения в информацию, относящуюся к данному модулю/
// необходимо изменить значения этих атрибутов *
//
[assembly: AssemblyTitie(*") 3
[assembly: AssemblyDescriptionC") ]
[assembly: AssemblyConfigurationC")]
[assembly: AssemblyCompany(**)]
[assembly: AssemblyProduct(**)]
[assembly: AssemblyCopyright("*)]
[assembly: AssemblyTrademark(*")]
[assembly: • AssemblyCulture("")]
Для краткости здесь приводится только часть файла. Внутри файла находится
некоторое количество строк, начинающихся с текста -[assembly:*,— это и есть
определения атрибутов. Когда такой файл компилируется, все описанные атрибуты
сохраняются в получающемся модуле. Этот процесс известен под названием 'кон-
сервирования' ('pickling'). Чтобы увидеть это в действии, измените один из приве-
денных выше атрибутов (например, атрибут AssemblyTitie) и откомпилируйте
модуль:
[assembly: AssemblyTitie("Wrox rocks*)]
После завершения компиляция щелкните
мышью на модуле в Windows Explorer, что при-
ведет к выводу на экран окна со свойствами. На
рисунке справа показана вкладка с информацией
о версиях. В поле Description находится описание
содержимого атрибута AssemblyTitie.
Информация о версии
AssemblyTitie
AssemblyDescription
As s emblyCompany
As semblyTrademark
AssemblyVers ion
AssemblyCopyright
As semblyProduct
Description (описание)
Comments (комментарии)
Company Name (название компании)
Legal Trademarks
(официальные торговые марки)
Assembly Version and Product Version
(версия модуля и версия продукта)
Copyright (копирайт)
Product Name (наименование продукта)
(Jennet V««*i | $««jsy j $им*дг/|
.5
i tcrmsriis
iilliiiiiiiilil
ж ~3
::l
. Й Ш ц © ! ! ;,::.:-:,...::.\,:;;:,,:;.1::::::>::;..:.;я
В таблице слева перечислены
атрибуты модуля и соответствую-
щие им имена на вкладке с инфор-
мацией о версии.
Атрибуты 615
Перечень атрибутов, предстапленных в окне со свойствами, оказывается несколь-
ко меньше, чем перечень атрибутов, описанных в модуле. Компанией Microsoft
предусмотрено отображение в окне свойств только некоторых, наиболее часто ис-
пользуемых атрибутов, а для того чтобы добраться до остальных атрибутов, требу-
ется либо написать некоторый код (этот код приводится в следующем разделе),
либо воспользоваться ildasm.
Для того чтобы найти все атрибуты, относящиеся к данному модулю, можно ис-
пользовать ildasm, который позволяет просмотреть модуль и найти все описанные
в нем атрибуты. Если вы до сих пор не включили ildasm в VS в качестве внешнего
инструмента, то следует воспользоваться инструкциями о том, как это следует де-
лать, приведенными в предыдущей главе.
Откройте ildasm и выберите модуль с помощью меню File | Open. После этогс
на экране можно увидеть следующее:
File View He'p
* 22\Code\Visua!S
? * i i i i U
1 Ш->9 Assemblylnlo
.;ГУ:; ••.•• - - --•..•.:••. .,-.•=: • •• ^ J O ]
tudio'vAssemblylnfoVbinVD ebugVteernbly i Ыо.еке
4^$5en';bi>! Assembly] n/o
j
Щелкнув два раза мышью на выделенном разделе MANIFEST, вы откроете окно
более низкого уровня, в котором находится манифест модуля, подробно описанный
в предыдущей главе. Немного прокрутив это файл вниз, вы увидите несколько
странно выглядящих строк кода:
.assembly AssemblyInfo
.custom instance void
[mscorlib] System. Reflection, AssemblyCopyright At tribute: :;.ctor (string)
= (01 00 00 00 00)
.custom instance void
[mscorlib]System.Reflection. AssemblyKeyNameAttribute::.ctor(string)
= (01 00 00 00 00) . V
.custom instance void
[mscorlib]System.Reflection. AssemblyTitleAttribute::.ctor(string)
= (01 00 0A 57 72 6F 78 20 72, 6F 63 6B 73 00 00) // Wrox rocks.
.hash algorithm 0x00008004
.ver 1:0:522:37167
Просматривая файл, вы сможете обнаружить целый ряд объявлений, которые
несколько напоминают объявления типа:
[mscorlib]System.Reflection. AssemblyTitleAttribute::.ctor(string)
= (01 00 0A 57 72 6F 78 20 72 6F 63 6B 73 00 00) // Wrox rocks. .
в 16 Глава 22
Значение атрибута AssembiyTitie, которое мы перед этим ввели, оказалось со-
храненным в манифесте модуля. Если вы воспользуетесь таблицей перекодировки
из шестнадцатеричных значений в кодировку ASCII, то обнаружите, что набор
символов, расположенный после '01 00 0А', представляет собой не что иное, как
текст 'Wrox rocks', представленный в кодировке ASCII. Начальные байты '01 00'
представляют собой двухбайтовый идентификатор, а '0А' определяет длину строки
(десять символов). Такая процедура сохранения атрибутов известна под названием
'pickling' (консервирование) — этот термин может встретиться в различных мате-
риалах по .NET, имеющихся в web.
В приведенном выше участке кода из файла Assembly inf о. cs было использовано
слово AssembiyTitie, хотя в коде на IL класс представляется в виде Assembiy-
TitleAttribute. Компилятор С# сначала осуществляет поиск класса с названием
AssembiyTitie, а затем, если поиск не дал результатов, добавляет слово Attribute
и осуществляет поиск повторно. Поэтому, независимо от того, набираете ли вы
название класса полностью или опускаете последнее слово Attribute, в обоих слу-
чаях будет сгенерирован один и тот же код. На протяжении настоящей главы это
слово будет опускаться.
Сохраненное (законсервированное) в манифесте объявление атрибута подозри-
тельно напоминает объект вместе со его конструктором, а байты, заключенные
в скобки,— параметры, передаваемые конструктору.
Теперь, получив общее представление об атрибутах, мы можем дать атрибуту
следующее определение:
Атрибут — это класс, в котором могут храниться дополнительные данные
внутри модуля, имеющие отношение к данному модулю или к типам,
содержащимся в данном модуле.
С учетом того, что атрибут — это класс, а в манифесте атрибут хранится
в представленном выше формате, можно пересмотреть определение атрибута, дан-
ное выше в настоящей главе:
[assembly: AssembiyTitie("Wrox rocks")]
Этот синтаксис несколько отличается от обычного синтаксиса С#, поскольку он
предполагает использование квадратных скобок, в которые заключается атрибут.
Тег assembly: определяет область действия данного атрибута (которая будет рас-
сматриваться ниже в данной главе), а в остальной части записи объявляется соб-
ственно атрибут. У атрибута AssembiyTitie есть конструктор, которому передается
только один параметр — строковое значение. Компилятор включает это значение
в модуль. Доступ к значению может быть осуществлен с помощью стандартного
окна свойств Windows, при просмотре этого модуля с помощью iidasm или про-
граммным путем с помощью отражения.
Кроме простых атрибутов, задающих информацию модуля, в .NET Framework
описано около двухсот атрибутов, которые используются в самых разнообразных
ситуациях — при отладке, при разработке способов временного контроля, преоб-
разовании в последовательную* форму и для многого другого. Мы познакомимся
с некоторыми стандартными атрибутами после раздела, посвященного отражению,
а затем перейдем к рассмотрению вопроса о том, каким образом программист мо-
жет расширить возможности .NET с помощью собственных атрибутов.
Атрибуты в 17
Отражение
Если вы не знакомы с основами языка программирования Java, то отражения
окажутся для вас новой темой, поэтому мы посвятим несколько страниц описанию
того, что это такое и каким образом оно может быть использовано.
Отражение позволяет осуществлять просмотр модуля программным путем
и получать о нем всю информацию, включая информацию о всех типах объектов,
которые в нем содержатся. В этой информации содержатся также и все атрибуты,
которые вы добавили к этим типам. Объекты отражения хранятся внутри про-
странства имен System.Reflection.
Помимо получения информации о типах, описанных внутри модуля, у програм-
миста имеется возможность генерировать свои собственные модули и типы с по-
мощью пространства имен System.Reflection.Emit. Эта тема кажется не совсем
подходящей для введения в С#, но если вас она заинтересует, то некоторую ин-
формацию по вопросу создания динамических модулей вы сможете найти в MSDN.
Практикум: поиск атрибутов
Первый пример данного раздела будет посвящен просмотру модуля и выводу
перечня всех атрибутов, определенных внутри данного модуля; в результате будет
получен список, аналогичный приведенному ранее. Код примеров, использованных
в данном разделе, можно загрузить с web-сайта Wrox Press, он располагается в ди-
ректории chapter22/FindAttributes. Ниже полностью воспроизведен исходный
файл:
//FindAttributes.cs
// Импортирование типов из System и System.Reflection
using System; : .
using System.Reflection;
/// <summary>
/// Предназначается для раздела главы 22, которая называется отражение
•••/// </summary>
public class FindAttributes
{
/// <summary>
/// Основная точка входа в выполняемый файл „ехе
///</summary>
/// <param name="argsn>Аргументы командной строки — должны
///представлять собой модуль</рагат>
static void Main (string [] args)
{
:••••// Вывод (при необходимости) информации, касающейся
//использования программы
if (args.Length == 0)
• :• • • ; • • • : • • • • Usage ( ) ; • • • • ' • ' • , : . : '• • . • .•• • •• '•• •• : • : •' .•• • :. . . • • • • .• • / • • . • • • • . • : . • /
else if ( (args.Length == 1) && (args[0] == "/?"))
Usage () ;
: • : ••' . . ' •: ' e l s e • ' : • ' ' • ' , • ^ ' ' : . ' ' V . ' , , . ' . : \ • ' ' . : . • , '• •• . ' ' •' :, ' ' •• • \ ' . ' • '• ' ' '
{ •. ' ' : • • . . ; • - • ;
// Загрузка модуля
string assemblyName = null ;
:•••,. •:-,:•./•/ Цикл просмотра аргументов, передаваемых консольному приложению.
// Просмотр аргументов осуществляется с предположением,
// что приложению передается полное имя пути, включающее пробелы
//и представляющее собой несколько разных аргументов — из них
// просто снова составляется единое имя файла...
618 Глава 22
' : : • . foreach (string arg in args) : . '\r,[.••::•••;.,•/:'/,.';••.'•';.. , ,: ' : - • :•:; : . . ••••...••.. • ;• :v :
( , : r - f \ : j . l - M'.;. :/:'.V" ••:•.-: • :; :' ' :
;y V : - O : : : v : ; - - • ' . н : ;;;; :-;-':.
.if ..(assemblyName == null)
., ., ; •''•[•'•'••i •;•;••;:: . — л / ; - a s s e m b l y N a m e = a r g ; : " ' • •
• .. ; ' e l s e . : ' ' ;;• . . •• • :'.'...• •• : '. •. .. •
assemblyNanie = string. Format (*{0) {1}", assemblyName r arg);
• t r y ;
f '• ••.•.:•:•.•'•': •..••• : : ' ' : : ''' : . ' : :: . : • : • ' ' . ' . •: . . . , . • • ' '.' '
//Попытка загрузить модуль с данным именем
Assembly а - Assembly.'LoadFrот (assemblyName) ;
II Теперь осуществляется поиск атрибутов модуля
//В данном случае параметр игнорируется, поэтому
//онпроизвольно задан как true
object[] attributes = a.GetCustomAttributes(true);
// Если удалось обнаружить описания каких-либо атрибутов...
if (attributes.Length > 0)
{
Console.WriteLine (*Assembly attributes for '{0}'..." ,
. •.:.,..••.,. : • : •:.:.' a s s e m b l y N a m e ) ;
// то следует вывести их...
foreach (object о in attributes)
Console.WriteLine (" {0}" , o.ToString ()); .
> :' , • • • . - • ' • : , ; • • . ' : . : ; . • • • . • • • : ; • : • ; . • • • . • • : ; • ; • • • • • • • • • • • • • . ; . : . ; . ; ^ ; ; .
else
Console.WriteLine ("Assembly {0} contains no Attributes." ,
assemblyName) ;
} ^.- ..^ " V; • ,^\.K'\, : " ; :
catch (Exception ex)
{
Console.WriteLine ("Exception thrown l o a d i n g assembly { 0 } . . . * ,
V ; : , . •• assemblyName); '••. • ', •;'•.:••••". : \ •.. •
C o n s o l e . W r i t e L i n e ( ) ;
C o n s o l e . W r i t e L i n e . ( e x . T o S t r i n g •(')-);
.) : . ' ' W ' . • • • ' • . • - . • " • '
:':/// <summary>
III Вывод полезной информации для .ехе
/// </summary>
static void Usage ()
Ш : Ж ^ ' ^ ^ ' ^ Щ - - : Щ ' : ••••':.:•:"-',•••••. / / • • • ^ • - • ' . • . " • • ' • ; - : - Ч
Console.WriteLine ("Usage:*);
Console.WriteLine (й FindAttributes <Assembly:^);
Как это работает
В программе сначала производится проверка наличия параметров, переданных
через командную строку, если таковые отсутствуют или пользователь ввел сроку
'FindAttributes /?', то происходит вызов метода usage, который выводит простое
сообщение об использовании данной команды:
if (args.Length == 0)
Usage () ;
else if ( (args.Length ==1) && (args[0] == '/?•))
Usage () ;
Атрибуты 619
Далее происходит объединение аргументов командной строки в единую строку.
Это необходимо выполнить, поскольку пробелы в названиях директорий весьма
распространены, например, 'Program Files', а это приводит к тому, что такой
текст из-за пробела воспринимается как два разных параметра. Поэтому все аргу-
менты просматриваются в цикле и преобразуются в одну строку, которая исполь-
зуется в качестве имени модуля, подлежащего загрузке:
foreach ( string arg in args )
if ( assemblyName == null )
assemblyName = arg ;
else
assemblyName = string.Format ( "{0} {!}" , assemblyName , arg ) ;
Затем производится попытка загрузить модуль и извлечь все описанные в этом
модуле нестандартные атрибуты:
Assembly a = Assembly.LoadFrот (assemblyName) ;
// Теперь осуществляется поиск атрибутов модуля В данном случае
// параметр игнорируется, поэтому он произвольно задается как true
object[] attributes = a.GetCustomAttributes(true) ;
Все атрибуты, которые удается обнаружить, выводятся на консоль. Теперь
можно построить выполняемый файл в Visual Studio.NET или воспользоваться
компилятором командной строки:
esc FindAttributes.cs
В результате этот файл будет отком-
пилирован, и будет создан выполняемый
файл консольного приложения, который
вы сможете запустить.
Для того чтобы запустить приложе-
ние FindAttributes, необходимо задать
имя проверяемого модуля. С этой целью
здесь можно использовать сам модуль
FindAttributes.exe (см. рис. справа).
; ' - • ^ , : . , . : . • : • • : ч -
|
У-\Pindftttpibutes>f indattributes' findattributes.-exe
ft$senbly'' a t t r i b u t e s £oa% *f In'dattributes.exe1 »„-.
;;'; ^ys ten «Bia^n'o's t i c s . Debusgablef) tti*ibttte-;
U:\FandAt: t r i b u t e s X,,.
Хотя атрибут DebuggabieAttribute не был задан, он был включен в модуль ком •
пилятором С#. Это обязательно происходит, если выполняемый файл компилирует-
ся в отладочном режиме, хотя на момент написания данной книги все выполняемые
файлы имеют этот атрибут,
Можно внести в программу изменения, добавив в нее произвольное количество
атрибутов модуля. Попробуйте, например, внести в код примера такие изменения:
using System;
using System.Reflection;
[assembly.: AssemblyTitle ( "Wrox rocks"
public class FindAttributes
1 • I^:\Find&tti»ife«tes>£indattrib«tes £in<tatt**i?
йз$етЫ.5? .attributes..' £qr *f.iindatti*ibwteis .ex«
System. Reflection, fit demblyTitlefl'ttribute
ш
В этом случае, запустив программу,
вы сможете увидеть выходной поток,
приблизительно тот, что показан на ри-
сунке слева.
Позже мы вернемся к отражению,
чтобы продемонстрировать, как можно
извлекать атрибуты классов и методов,
описанных внутри модуля.
620 Глава 22
Встроенные атрибуты
.NET Framework включает в модуль несколько атрибутов, например среди них:
DebuggableAttribute И AssemblyTitleAttribute. В настоящем разделе МЫ обсуДИМ
некоторые из наиболее часто употребляемых атрибутов, описанных в .NET Framework,
и ситуации, когда у вас может возникнуть желание использовать их.
В данном разделе будут рассматриваться следующие атрибуты:
Ql System.Diagnostics.ConditionalAttribute
• System.ObsoleteAttribute
• System.SerializableAttribute
• System.Reflection.AssemblyDelaySignAttribute
За более подробной информацией об атрибутах, которые поставляются совмест-
но с .NET, следует обратиться к MSDN, либо инсталлировав ее одновременно
с инсталляцией .NET, либо воспользовавшись версией, работающей в режиме он-
лайн по адресу http://msdn.microsoft.com.
Другим чрезвычайно полезным инструментом при работе с .NET, является про-
грамма 'Reflector', которую можно переписать с http://www.aisto.com/roeder/dotnet/.
В ней для проверки содержимого модуля используются отражения. Она позволяет
найти все классы, производные от класса system.Attribute, с помощью несколь-
ких щелчков мышью. Это тот инструмент, без которого вы не сможете обойтись.
Атрибут System.Diagnostics.ConditionatAttribute
Это один из наиболее полезных атрибутов, поскольку он позволяет добавлять
и исключать участки кода в зависимости от значения флажка, определяемого на
этапе компиляции. Рассматриваемый здесь атрибут содержится в пространстве имен
system.Diagnostics, в которое включены классы, предназначенные для отладки
и трассировочного вывода, регистрации событий, счетчики скорости выполнения
и информация о процессе. В следующей программе приводится пример использо-
вания этого атрибута:
•• • • . , • • • , USing System; • • : „ . • • • • •., . • . . - . , • . • : . , . . • • • . ,. : ..-, . : • . • • • : . : : • • • . • ; : • , . . . : • ; : • . • • . • .
using System.Diagnostics; :
class TestConditional
• • • • • . { ' " • • • • & : •
static void Main (string [] args)
{
// Создание нового объекта TestConditional
TestConditional tc = new TestConditional ( ) ;
// Вызов метода, который доступен, только если определена
II переменная DEBUG.
tc.DebugOnly ( ) ;
// Class constructor (Класс "Конструктор"
public TestConditional ()
//Этот метод зависит от значения атрибута и будет включен
// в выходной код только в том случае, если при компиляции
Атрибуты 621
// программы был определен флажок DEBUG
[Conditional("DEBUG")]
public void DebugOnly ()
{
//Эта строка будет выводиться только в случае построения
// отладочных версий...
Console.WriteLine ("This string only displays in Debug") ;
-; "*)** -зй
Cat&g&S&ax |A«ttwB<Oebug; 2J ку/с* ""d Corligurab&i Ндодвг..«
tVXX Pr
ИСХОДНЫЙ текст ДЛЯ ЭТОГО примера наЙДИТе В директории Chapter22/Conditional.
В программе создается экземпляр класса Testconditionai внутри статической
функции Main. Затем вызывается метод DebugOnly, который зависит от атрибута
Conditional. Это функция просто выводит текстовую строку на консоль.
При компиляции исходного файла на С# можно определять флажки в команд-
ной строке. Атрибут Conditional запрещает вызов зависящего от флажка метода
при отсутствии соответствующего флажка.
Флажок DEBUG будет установлен
автоматически, если вы компилируете
отладочную версию в Visual Studio.NET.
Если вы хотите определить или переоп-
ределить какие-либо флажки для конк-
ретного проекта, то необходимо открыть
диалоговое окно, позволяющее задавать
свойства проекта с помощью опции Build
в разделе Configuration Properties, как
показано на рисунке слева.
Заметьте, что по умолчанию при по-
строении отладочной версии предпола-
гается определение флажков DEBUG
и TRACE.
Для определения флажка в команд-
ной строке необходимо воспользоваться
переключателем /d: (сокращение от /define: можно при желании набрать всю
строку полностью):
esc /d:DEBUG /r:System.dll conditional.es
Если откомпилировать и запустить файл с использованием указанной команд-
ной строки, то на консоли можно увидеть следующий выходной поток:
This string only displays in Debug
(Это строка выводится только в отладочном режиме)
| CJwft .'Of A- .ttv r: < O-^rr k..-- i" ?. Ъ fкм< Fefee
| A?ow u r ; ^ t cede btocks FaJse
W<jf r «Trfj Level WafnsrXf •
| CXApo! Path Ь>п\О«Ъи
* '.PI, «,,r.
: SfX<^Y synrfco^ c<n which to peffwm ссоА^юпл! cornp
«vd 4
зГ *"
,:•:•,;.:;л;:;Ч-:;.;;;; л,;;:..:;.;.,
i
••• I
I f f
:
Men»
Если откомпилировать программу без
определения флага DEBUG в команд-
ной строке, то программа ничего не
выведет.
Для того чтобы стало более понят-
но, что именно происходит в создавае-
мом коде, просмотрите его с помощью
iidasm (см. рис. справа).
File View He!p
в—ф conditional.exe
I • MANIFEST
S-'U TestConditional
Ь . class private auto ami befomfieldinil
Ш .dor. void()
.assembly conditional
L f _ _ .
622 Глава 22
Если флажок DEBUG не задан, то для метода Main о генерируется следующий
IL-код:
.method private hidebysig static void Main{string[] args) cil managed
{
.entrypoint
// Code size 7 (0x7)
.maxstack 1
.locals (class TestConditional V_0)
IL__0000: newobj instance void TestConditional::.ctor()
IL_0005: stloc.O
IL_0006: ret
} // end of the method TestConditional: :Main
Этот код просто создает экземпляр объекта TestConditional (IL_OOOO) , помещает
его в локальную переменную и производит возврат.
Если при компиляции будет задан переключатель /d:DEBUG, TO будет сгенериро-
ван код, приведенный ниже:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 13 (Oxd)
.maxstack 1
.locals (class TestConditional V_0)
IL__0000: newobj instance void TestConditional::.ctorО
IL_0005: stloc.O
IL__Q006: ldloc.O
: IL__0007-.callvirt instance void TestConditional: :DebugOnly()
IL_000c: ret
> // end of the method TestConditional: :Main
В этот код дополнительно включены две выделенные строки, в которых происходит
вызов метода по условию. Использование conditional приводит к удалению строк,
ответственных за вызов метода, но не самого метода.
Атрибут conditional может использоваться только для тех методов,
которые ничего не возвращают (описатель void), в противном случае
удаление обращения к такому методу будет означать, что не возвращено
никакого значения. Существует возможность сделать зависимым от атрибута
метод, который обладает параметрами типа ref или out; в этом случае
эти переменные просто сохранят свое первоначальное значение.
Атрибут System.ObsoleteAttribute
Включение описания этого атрибута в новую книгу по новому языку програм-
мирования может показаться на первый взгляд странным, хотя, на самом деле, это
свидетельствует о том, какое внимание разработчики компании Microsoft уделили
' .NET. С помощью атрибута obsolete может помечаться класс, метод или любое
другое вхождение модуля, которое больше не используется.
Этот атрибут может оказаться полезным при создании библиотеки классов.
В ходе процесса разработки множества классов некоторые из классов/методов/
свойств будут вытесняться новыми. Данный атрибут может быть использован для
того, чтобы подготовить пользователей данного кода к фактическому удалению какой-
либо конкретной возможности.
Атрибуты
Скажем, в версии 10 вашего приложения есть следующий класс:
public class Developer
{ .
public Developer ()
{
Ж^;Ш \/:^ШШ Ш%г'.-:: •:••/.•: ":^.:.. :''!••:: : P S S : ? # : : : i'-'v' ^••.•
public void OriginalMethod 0
Вы компилировали и использовали этот класс на протяжении нескольких лет,
однако теперь появляется нечто более новое:
public void NewMethod ()
Вы, естественно, хотите разрешить пользователям вашей библиотеки работать
с методом OriginalMethod() на протяжении еще некоторого времени, но вы также
желаете уведомить их о том, что появился более новый метод, с помощью выдачи
предупредительного сообщения в процессе компиляции, информирующего пользо-
вателей о существовании метода NewMethod о . Все, что для этого потребуется,—
это добавить атрибут obsolete, как это показано ниже:
[Obsolete("Вместо этого следует использовать метод NewMethod. *) 3
public void OriginalMethod ()
При компиляции отладочной или окончательной версии компилятор С# выдаст
предупреждение, что вы используете устаревший метод (или метод, который уста-
реет через некоторое время):
obsolete.cs(10,3): warning CS0б18: 'Developer.OriginalMethod() is obsolete:
(Метод Developer. OriginalMethodQ устарел:)
'Use NewMethod instead'
('Вместо этого следует использовать метод NewMethod')
С течением времени всем пользователям надоест видеть это предупредительное
сообщение при каждой компиляции их программы, и в конечном итоге все пользо-
ватели (на самом деле, почти все) перейдут на использование метода NewMethodO.
Спустя еще какое-то время вы примете решение окончательно отказаться от под-
держки метода originalMethodO, для чего вам потребуется включить в атрибут
obsolete дополнительный параметр:
[Obsolete("Вместо этого следует использовать метод NewMethod.*, true)]
public void CodlnC ()
Теперь, если какой-нибудь пользователь попытается откомпилировать этот ме-
тод, компилятор сгенерирует ошибку и прекратит процедуру компиляции с выдачей
следующего сообщения:
obsolete.cs(10,3): error CS0619: 'Developer.OriginalMethodO is obsolete:
(Метод Developer.OriginalMethod() устарел:)
'You must use NewMethod instead. '
('Вместо этого следует использовать метод NewMethod')
624 • Глава 22
Использование этого атрибута обеспечивает предоставление помощи пользова-
телям при изменении класса в процессе осуществления модификации их собствен-
ных приложений, где этот класс используется.
Для классов, представленных в двоичном виде, например, для компонентов, при-
обретаемых без исходных текстов, такой способ работы с версиями не может быть
рекомендован. В .NET существуют встроенные возможности (обсуждаемые выше)
для работы с версиями. Подобные возможности предупреждают, что больше не сле-
дует пользоваться какой-либо возможностью созданных нами классов.
Атрибут System.SerializableAttribute
Сериализацией называется процесс сохранения объекта в дисковом файле, па-
мяти или в каком-либо другом месте. В процессе сериализации все данные экзем-
пляра сохраняются на некотором носителе, а в процессе десериализации объект
снова наполняется таким образом, что его становится невозможно отличить от
первоначального экземпляра.
Все, кому ранее приходилось программировать на MFC, ATL или VB и кто был
вынужден постоянно думать о том, каким образом сохранить или считать данные
некоего экземпляра, поймут, от какого объема вводимой информации может изба-
вить этот атрибут. Предположим, что у вас имеется некоторый объект, который
необходимо сохранить в файле и который описывается следующим образом:
public class Person
{
public Person () . ::
public int Age; ;>:
В С# (и в любом другом структурном языке программирования) есть возмож-
ность сериализовать члены данного экземпляра без написания какого-либо кода.
Все, что вас требуется,— это включить в класс атрибут serializable, а все осталь-
ное сделает за вас система выполнения программ .NET.
Когда в названную систему поступает запрос на сериализацию какого-нибудь
объекта, то она проверяет, реализован ли в классе данного объекта интерфейс
ISerializable, И если нет, ТО имеется ЛИ В ЭТОМ классе атрибут Serializable. Мы
не будем обсуждать интерфейс ISerializable — это слишком сложная тема для
данной книги, к тому же по этой теме уже существует вполне приличная докумен-
тация в MSDN.
Если в классе обнаруживается атрибут serializable, то .NET использует отра-
жение для того, чтобы получить все данные конкретного экземпляра — независи-
мо от того, описаны ли они как общие, защищенные или частные, и сохранить их
как представление этого объекта. Десериализация представляет собой процесс,
обратный описанному,— данные считываются с носителя информации и присваи-
ваются переменным экземплярам данного класса.
Ниже ПРИВОДИТСЯ пример Класса, Помеченного атрибутом Serializable:
[Serializable]
public class Person
{
public Person
public int Age;
public int WeightlnPounds;
который преобразовьГа ;
байтов. Система поставляетесДВУМЯ™
умолчанию,- Bina^orTtJe^ s Z o ™ Г " . ТЗКИХ
странством имей в пространстве Т
Программа, приведенная^^
public static void Serialize ()
// Создание объекта класса Person
Person me = new Person ();
me.WeightlnPounds = 200;
// Сериализация объекта
// и закрытие потока
s.Close () ;
и с п о л ьзуемых по
С В ° И М ПР°"
можно И С П О Л Ь З ° -
Как это работает
, и
нако „р„
п м е й , в е
[Serializable]
public class Person
{
public Person ()
о б ъ е к т
Л° .се содержи-
public int Age;
CNonSerilized]
Public int WeightlnPounds;
при десериализации. ' с л е д о в а т е л ь н о , не будет извлекать-
626 Глава 22
Десериализация, в основном, обратна коду, приведенному выше. Следующий
пример Открывает ПОТОК В ВИДе файла Me.dat, СОЗДает BinaryFormatter ДЛЯ СЧИТЫ-
вания объекта и вызывает метод Deserialize, позволяющий извлечь этот объект.
После этого считанные данные приводятся к типу Person, и на консоль выводятся
возраст и вес:
public static void DeSerialize •{•)•
// На этот раз сначала открывается файл
Stream s = File.Open ("Me.dat" , FileMode.Open);
// BinaryFormatted используется для чтения объекта (объектов) из потока
BinaryFormatter bf - new BinaryFormatter () ;
// Десериализация объекта
object о = bf.Deserialize (s) ;
//Убеждаемся в том, что объект нужного нам типа. ..
Person р = о as Person ;
• ••• • • • • • • • г • • i f ( р ! = n u l l ) 1 ' •: ч •: : • • •:•: •. •'•'•,::. ,.:•'. . : • • } . • • . : " • • • • • . • : • • •••••• : ••• .
Console.WriteLine ("DeSerialized Person aged: {0} weight: {!}" ,
p.Age , p.WeightInPounds);
// Закрытие потока
s.Close () ;
Обычно посредством NonSeriiized (не подлежащие сериализации) помечаются
данные, которые получаются в результате вычислений, поскольку они могут вы-
числены по мере возникновения такой необходимости. В качестве примера можно
привести класс, в котором вычисляются простые числа; их вполне можно сохра-
нять для увеличения скорости ответа при обращении к данному классу, однако
сериализация и десериализация списка простых чисел не является необходимой,
поскольку они всегда могут быть вычислены в момент обращения к классу. В дру-
гих случаях некоторый член может иметь отношение только к данному экземпляру
документа. Например, для объекта, который представляет документ, обрабатывае-
мый редактором, потребуется сериализовать содержимое самого документа, но не
текущую позицию, поскольку при очередной загрузке документа в качестве такой
позиции просто используется начало документа.
Если необходим более полный контроль за сериализацией документа, то следу-
ет реализовать интерфейс iseriaiizabie. Это очень сложная тема, и в настоящей
книге ее рассматривать не будем.
Атрибут System.Reflection.AssemblyDelaySignAttribute
В пространстве имен System.Reflection существует несколько атрибутов, уже
упоминавшихся в настоящей главе. Одним из наиболее сложных в использовании
является атрибут AssembiyDeiaySign. В предшествующей главе вы познакомились
с тем, каким образом создаются модули и глобальные модули, а также каким обра-
зом их можно зарегистрировать в Global Assembly Cache (GAC — кэш глобальных
модулей). .NET Framework, кроме того, позволяет помечать модуль как "отсрочен-
ный", что, в основном, означает, что вы получаете возможность регистрировать
его в GAC для отладочных целей без частного ключа.
Атрибуты 627
Одним из сценариев, при котором возможно использование помеченных таким
образом модулей, является разработка коммерческого программного обеспечения.
Каждый модуль, разрабатываемый в домашних условиях, должен быть помечен
частным ключом вашей компании, прежде чем он будет отправлен клиентам. По-
этому при компиляции модуля вы ссылаетесь на файл с. ключом, до того как заре-
гистрировать модуль в GAC.
Однако многие организации не хотят, чтобы их частный ключ использовался на
всех компьютерах разработчиков. По этой причине система выполнения программ
позволяет помечать модуль частично, для чего выбирается несколько установок,
которые позволяют зарегистрировать модуль в GAC. После тестирования он мо-
жет быть помечен тем, кто является хозяином файла с ключом. Это может быть
информационный отдел вашей компании, одно или несколько доверенных лиц или
отдел маркетинга.
В следующем примере продемонстрировано, как можно обычный модуль поме-
тить как "отсроченный", затем зарегистрировать его в GAC для осуществления от-
ладки, после чего окончательно пометить добавлением частного ключа.
Практикуй: создание файла с ключом
Создание файла с ключом
Прежде всего необходимо создать файл с ключом с помощью утилиты sn.exe,
которая обычно инсталлируется В директории Program Files\Microsoft.NET\FrameworkSDK\
Bin. В этом файле будут храниться общие и частные ключи, поэтому мы
назовем его Company.Key!
sn -k Company.Key
Теперь необходимо извлечь ту часть общего ключа, которая будет использоваться
разработчиками:
sn -p Company.Key Company.Public
Эта команда приведет к созданию файла с ключом company.Public, в котором
будет содержаться только общедоступная часть ключа. Этот файл с общим ключом
может быть скопирован на все компьютеры и не требует каких-то мер по обеспе-
чению безопасности — оберегать следует файл с частным ключом. Спрячьте файл
company.Key подальше, поскольку он понадобится, только когда вы захотите окон-
чательно пометить свои модули.
Для того чтобы пометить модуль как "отсроченный" и зарегистрировать его
в GAC, необходимо также получить маркер общего ключа, который обычно пред-
ставляет собой укороченный вариант общего ключа, используемого для регистра-
ции модулей. Получить маркер можно одним из следующих способов:
• Непосредственно из общего файла с ключа
sn -t Company.Public
• Из любого модуля, помеченного этим ключом:
sn -Т <assembly>
Оба способа позволяют получить хешированную версию общего ключа, причем
они чувствительны к регистру. Это будет объяснено более подробно при описании
регистрации модуля. .
628 Глава 22
Практикум: создание "отсроченных" модулей
Приведенный ниже пример демонстрирует, *каким образом можно с помощью
атрибутов пометить модуль как "отсроченный". Этот пример находится в директо-
рии Chapter22/DelaySign:
using System;
using System.Reflection;
// Определение файла, в котором содержится частный ключ
[assembly: AssemblyKeyFile ("Company.Public1*)]
//и того факта, что данный модуль должен быть помечен как " отсроченный".
[assembly: AssemblyDelaySign (true)]
public class DelayedSigning
{
public DelayedSigning ()
Как это работает
Атрибут AssembiyKeyFile позволяет определить, в каком файле следует искать
ключ. Это может быть либо файл, содержащий общий ключ, либо — для наиболее
доверенных лиц — файл, в котором содержатся как общий, так и частный ключи.
Атрибут AssemblyDelaySign определяет, будет ли данный модуль помечен обычным
образом (false) или как "отсроченный" (true).
Если для всех проектов вы используете Visual Studio.NET, то в таком случае
создается файл с именем Assembiyinfo.cs, в котором описываются различные
атрибуты, в частности, атрибуты, предназначенные для работы с номерами версий
и для хранения информации о файле, которые рассматривались в этой главе. Кро-
ме ТОГО, именно В данном файле Определяются атрибуты AssemblyDelaySign, При
этом для каждого нового проекта создаются новые значения, используемые по
умолчанию.
После завершения компиляции модуль будет
обладать вхождением для общего ключа, который
находится в манифесте. На самом деле, в манифе-
сте будет еще достаточно свободного места и для
общего ключа, поэтому повторная пометка модуля
не приведет к каким-либо существенным измене-
ниям (кроме записи нескольких дополнительных
байтов в манифест). '
В нижней части экрана (см. рис. слева) пред-
ставлен общий ключ, хранящийся в манифесте.
Необходимо отметить, что в верхней части экрана
располагается ссылка на mscoriib.dll. В этой
библиотеке содержится большая часть объектов
пространства имен system (и его производных).
При этом выводится не только информация о версии данного модуля, но и маркер
его общего ключа, который представляет собой последовательность байтов. Если
модули сторонних производителей ссылаются на ваш модуль, в них также должна
указываться хешированная версия вашего общего ключа. *
Если для просмотра модуля, ссылающегося на ваш модуль, используется iidasm,
то вы увидите в манифесте вхождение, в котором содержится маркер общего ключа.
t%
..eusto* *tsst*&ce
MM aoorlib
> (В? 7Д SC
i
void f»s©o«-
л» the lolloving custo*
ss -cwiSto», instance void t*-
\ publickmv - ( 6 0
! ' so
; IS
i и
в® j №
ев
u ; x
; ver oV?oro* *
24 08 00 U
Zi 00 Ш $?
$C Dl № C3
П 7Е 0f 68
22 6? Ш? 8"3
ЗЕ П F£ 7$
Ы X)K 10 4?
2i OB i t CS
10 91 C* D8
48 Ш H Ы
XU«UwoUU4
\
и
lib
so
%%
nI
S
n
Л 7

Sa
9
k.
_ . Ш
00
41
12
SF
47
| 4
7{?
Vlt
C2
Ы
.
OS
i% ОС
OS
?A
?A
B7

H
. F0
51
03

&.»
M.
00
0-t
Si
BD
сг Si
Ы
?iA<
00
0Q
4€

4-V
4f C$
'/8
$2
00
F'?
4&
SB
•?c
so 953
sft
ем
stir
M
w
C9
M
ASd
u
F$
EC
A. 2?
ttO
It
D7
CC
S3
•y. <k
00
IE J
D3 )
:":ir
Атрибуты 629
Для того чтобы добавить ссылку на другой модуль из командной строки, следует
ВОСПОЛЬЗОВаТЬСЯ ОПЦИеЙ /г, как, например, В /г:System.Data.dll:
.asembly extern DelaSign
{
.publickeytoken = (34 AA A4 14 6E EO IE 4A)
.ver 0:0:0:0:
}
Регистрация в GAC
Попытка использования инструмента gacutii, который находится в директории
FrameworkSDK\Bin, для регистрации "отсроченного" модуля приведет к следующему
сообщению об ошибке:
Microsoft (R) .NET Global Assembly Cache Utility. Version 1.0.2914.16
Copyright (C) Microsoft Corp. 1998-2001. All rights reserved.
Failure adding assembly to the cache: Strong name signature could not be verified.
(Неудача при попытке включить модуль в кэш: Невозможно проверить правильность
сигнатуры строгого имени.)
Was the assembly built delay-signed?
(He является ли построенный модуль "отсроченным"?)
К этому моменту данный модуль является только частично помеченным, а по
умолчанию GAC принимает только те модули, у которых имеется полное ст
Категория: информатика | Просмотров: 1154 | Добавил: basic | Рейтинг: 0.0/0
Всего комментариев: 0
Имя *:
Email *:
Код *:
Календарь
«  Февраль 2010  »
ПнВтСрЧтПтСбВс
1234567
891011121314
15161718192021
22232425262728
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0

krutoto.ucoz.ru
Бесплатный конструктор сайтов - uCoz