Assembly
-------------------------------------------------------------
Token: 0x20000001
Name: CarLibrary
Public Key: 00 24 00 00 04 80 00 00 // и т.д.
Hash Algorithm: 0x00008004
Major Version: 0x00000002
Minor Version: 0x00000000
Build Number: 0x00000000
Revision Number: 0x000000000
Locale: ‹null›
Flags: [SideBySideCompatible] (00000000)
Представление ссылок на другие компоновочные блоки
Вдобавок к метке Assembly и набору меток TypeDef и TypeRef метаданные .NET используют метки "AssemblyRef #n", чтобы обозначить внешние компоновочные блоки. Например, поскольку CarLibrary.dll использует тип MessageBox, в окне метаданных вы обнаружите метку AssemblyRef для System.Windows.Forms.
AssemblyRef #2
-------------------------------------------------------------
Token: 0x23000002
Public Key or Token: b7 7a 5c 56 19 34 e0 89
Name: System.Windows.Forms
Version: 2.0.3600.0
Major Version: 0x00000002
Minor Version: 0x00000000
Build Number: 0x00000e10
Revision Number: 0x00000000
Locale: ‹null›
HashValue Blob:
Flags: [none] (00000000)
Представление строковых литералов
В заключение нашего обсуждения метаданных .NET укажем на то, что все строковые литералы базового программного кода представляются в окне метаданных ildasm.exe под знаком метки User Strings, как показано ниже[1].
User Strings
70000001: (11) L"Car 2.0.0.0"
70000019: (11) L"Jamming {0}"
70000031: (13) L"Quiet time…"
7000004d: (14) L"Ramming speed!"
7000006b: (19) L"Faster is better."
70000093: (16) L"Time to call AAA"
700000b5: (16) L"Your car is dead"
700000d7: (9) L"Be quiet "
700000eb: (2) L"!!"
Пока что не слишком беспокойтесь о точном синтаксисе каждого элемента метаданных .NET. Более важно то, что метаданные .NET дают очень подробное описание всех типов, определенных внутри базового кода, и всех данных, на которые в этом базовом коде имеются ссылки.
Теперь у вас должен возникнуть следующий вопрос: если вообще нужно что-то знать о метаданных, то как использовать эту информацию в приложениях? Чтобы получить ответ, давайте рассмотрим такое понятие, как сервисы отображения .NET. А вопрос о пользе предлагаемых ниже подходов мы оставим открытым до рассмотрения соответствующих примеров в конце этой главы. Поэтому наберитесь терпения.
Замечание. В окне MetaInfo утилиты ildasm.exe вы обнаружите также ряд меток CustomAttribute, которые используются для обозначения атрибутов, примененных в базовом программном коде. Роль атрибутов .NET мы обсудим в этой главе немного позже.
Отображение типов в .NET
В терминах .NET отображение обозначает процесс выяснения параметров типа средой выполнения. Используя сервисы отображения, ту же информацию метаданных, которая отображается с помощью ildasm.exe, вы можете получить программно. Например с помощью отображения можно получить список всех типов, содержащихся в данном компоновочном блоке (или в файле *.netmodule), включая методы, поля, свойства и события, определенные данным типом. Можно также динамически выяснить, какой набор интерфейсов поддерживается данным классом (или структурой), выяснить параметры метода и другие аналогичные подробности (базовые классы, информацию пространства имен, данные манифеста и т.д.).
Подобно любому другому пространству имен, System.Reflection содержит ряд связанных типов. В табл. 12.1 приводится список элементов этого пространства имен, о которых вам следует знать.
Таблица 12.1. Некоторые элементы пространства имен System.Reflection
Тип Описание Assembly Этот класс (вместе с множеством связанных типов) предлагает ряд методов, позволяющих загружать, исследовать и обрабатывать компоновочный блок AssemblyName Класс, позволяющий выяснить многочисленные подробности, касающиеся идентификации компоновочного блока (информацию о версии, параметры локализации и т.д.) EventInfo Класс, содержащий информацию об указанном событии FieldInfo Класс, содержащий информацию об указанном поле MemberInfо Абстрактный базовый класс, определяющий общие характеристики поведения для типов EventInfo, Fieldlnfo, MethodInfo и PropertyInfo MethodInfo Класс, содержащий информацию об указанном методе Module Класс, позволяющий получить доступ к указанному модулю многомодульного компоновочного блока ParameterInfo Класс, содержащий информацию об указанном параметре PropertyInfo Класс, содержащий информацию об указанном свойстве
Чтобы понять, как использовать пространство имен System.Reflection для чтения метаданных .NET программными средствами, мы с вами должны сначала ознакомиться с возможностями класса System.Type.
Класс System.Type
Класс System.Type определяет ряд членов, которые могут использоваться для чтения метаданных типа, и многие из этих членов возвращают типы из пространства имен System.Reflection. Например, тип Type.GetMethods() возвращает массив типов MethodInfo, тип Type.GetFields() возвращает массив типа FieldInfo и т.д. Полный набор открытых членов System.Type очень велик. В табл. 12.2 предлагается небольшой список наиболее важных из них (подробности описания можно найти в документации .NET Framework 2.0 SDK).
Таблица 12.2. Избранные члены System.Type
Тип Описание IsAbstract IsArray IsClass IsCOMObject IsEnum IsGenerlcTypeDefinition IsGenericParameter Islnterface IsPrimitive IsNestedPrivate IsNestedPublic IsSealed IsValueType Эти свойства (наряду с другими аналогичными) позволяют выяснить ряд основных характеристик соответствующего объекта Туре (например, является ли этот объект абстрактным методом, массивом, вложенным классом и т.д.) GetConstructors() GetEvents() GetFields() GetInterfaces() GetMembers() GetMethods() GetNestedTypes() GetProperties() Эти методы (наряду с другими аналогичными) позволяют получить массив, представляющий все элементы соответствующего вида (интерфейсы, методы, свойства и т.п.). Каждый метод возвращает свой массив (например, GetFields() возвращает массив FieldInfо, GetMethods() возвращает массив MethodInfo и т.д.). Каждый из этих методов имеет также форму единственного числа (GetMethod(), GetProperty() и т.д.), которая позволяет извлечь один конкретный элемент по имени, а не все связанные элементы FindMembers() Возвращает массив типов MemberInfo на основе заданных критериев поиска GetType() Статический метод, возвращающий экземпляр Туре по заданному строковому имени InvokeMember() Позволяет выполнить динамическую привязку к заданному элементу
Получение Туре с помощью System.Object.GetType()
Экземпляр класса Туре можно получить множеством способов. Нельзя только непосредственно создать объект Туре, используя для этого ключевое слово new, поскольку класс Туре является абстрактным. Чтобы привести пример одной из допустимых возможностей, напомним, что System.Object определяет метод GetType(), который возвращает экземпляр класса Туре, представляющий метаданные соответствующего объекта.
// Получение информации типа с помощью экземпляра SportsCar.
SportsCar sc = new SportsCar();
Type t = sc.GetType();
Очевидно, что этот подход будет оправдан только в том случае, когда вы имеете информацию о соответствующем типе (в данном случае это тип SportsCar) во время компиляции. При этом становится ясно, что такие инструменты, как ildasm.exe, не могут получать информацию о типах путем непосредственно вызова System.Object.GetType(), поскольку ildasm.exe не компилируется вместе с пользовательскими компоновочными блоками.
Получение Туре с помощью System.Type.GetType()
Более гибкий подход обеспечивается использованием статического члена GetType() класса System.Type с указанием абсолютного имени соответствующего типа в виде строки. При использовании такого подхода для извлечения метаданных уже не требуется информация о типе во время компиляции, поскольку Type.GetType() использует экземпляр "вездесущего" System.String.