Метаданные в .NET (англ. .NET metadata) — термин, относящийся к платформе Microsoft .NET и обозначающий определённые структуры данных, добавляемые в код Common Intermediate Language для описания высокоуровневой структуры кода. Метаданные описывают все классы и члены классов, определённые в сборке, а также классы и члены классов, которые текущая сборка вызывает из другой сборки. Метаданные для метода содержат полное описание метода, включая его класс (а также сборку, содержащую этот класс), его возвращаемый тип и все параметры этого метода.
Компилятор .NET-языка создает метаданные и сохраняет их в сборку, содержащую CIL. Когда среда CLR исполняет CIL она делает проверку того, что метаданные вызываемого метода совпадают с метаданными, хранящимися в вызывающем методе. Это гарантирует, что метод может быть вызван именно с корректным числом параметров и именно с корректными типами параметров.
Атрибуты Разработчики могут добавлять метаданные в свой код благодаря атрибутам. Существует два типа (две формы) атрибутов: атрибуты, которые определены в среде CLR (т. н. англ. pseudo custom attributes), и пользовательские атрибуты (англ. custom attributes), создаваемые пользователем для добавления в код дополнительных сведений. С точки зрения разработчика оба типа имеют одинаковый синтаксис. Атрибуты в коде являются по сути сообщениями компилятору для создания метаданных. В CIL метаданные (такие как например, модификаторы наследования, модификаторы области видимости), а также почти все, что не является кодом операции или потоками, также помечаются как атрибуты.
Пользовательский атрибут представляет собой обычный класс, наследующий от класса Attribute. Такой атрибут может быть использован для любого метода, свойства, класса или сборки целиком при использовании следующего синтаксиса: [ИмяАтрибута(необязательный параметр, дополнительные пары имя=значение)]. Например:
Код
[Custom] [Custom(1)] [Custom(1, Comment="да")]
Пользовательские атрибуты весьма широко используются в платформе .NET Framework. Windows Communication Framework использует атрибуты для определения сервисных контрактов, ASP.NET использует их для предоставления методов как веб-служб, LINQ к SQL использует их для привязки классов к нижележащим реляционным схемам, Visual Studio использует их для группировки свойств объекта, разработчики классов указывают категорию для класса объекта при помощи пользовательского атрибута [Category]. Пользовательские атрибуты обрабатываются кодом приложения, а не CLR. Когда компилятор находит пользовательский атрибут, то он создает пользовательские метаданные, нераспознаваемые средой CLR. Разработчик должен реализовать код для чтения и обработки метаданных. В качестве примера, атрибут, показанный в примере выше, может быть обработан следующим кодом:
Код
class CustomAttribute : Attribute { private int paramNumber = 0; private string comment = "";
public CustomAttribute() { } public CustomAttribute(int num) { paramNumber = num; }
public String Comment { set { comment = value; } } }
Имя класса связано с именем атрибута. Компилятор среды разработки Visual C# автоматически добавляет строку «Attribute» в конец каждого имени атрибута. Как следствие, каждое имя атрибута класса должно оканчиваться такой строкой, но вполне допускается и определение атрибута без суффикса Attribute. При добавлении атрибута к какому-либо элементу компилятор ищет и по указанному имени и имени со словом Attribute на конце, то есть если написать [Custom], то компилятор будет искать и Custom и CustomAttribute. Если же они оба существуют, то компилятор сообщит об ошибке. Во избежание неоднозначности имена атрибутов могут помечаться префиксом «@», в результате чего [@Custom] будет не то же самое что и CustomAttribute. Использование атрибута вызывает конструктор класса, причем поддерживаются и перегруженные конструкторы. Пары «имя-значение» привязываются к свойствам, при этом «имя» обозначает имя свойства, а «значение» — присвоенное значение свойства.
Иногда появляется путаница относительно добавления атрибута. Например, в следующем коде непонятно, что именно обозначается как «orange»:
Код
[Orange] public int ExampleMethod(string input) { //тело метода описывается здесь }
В данном случае «orange» может означать какой-нибудь тестовый метод ExampleMethod, его возвращаемое значение или всю сборку целиком. В этом случае компилятор по умолчанию попытается обработать атрибут как атрибут метода. Если это не то, что предполагалось автором кода, или автор просто захотел сделать код более понятным, то допускается указание цели атрибута. Написание [return: Orange] укажет на то, что возвращаемым значением будет «апельсин», [assembly: Orange] укажет на всю сборку целиком. Допустимыми целями являются: сборка (assembly), поле (field), событие (event), метод (method), модуль (module), параметр (param), свойство (property), возвращаемое значение (return) и тип (type).
Заранее определённые атрибуты используются так же как и обычные атрибуты, но у них нет настраиваемого обработчика, поскольку компилятор содержит в себе уже встроенное описание таких атрибутов и обрабатывает код в зависимости от установленной метки. Такие атрибуты как Serializable и Obsolete реализуются именно как заранее определённые атрибуты. Заранее определённые атрибуты не должны использоваться ассемблером ILASM, поскольку у него есть собственный синтаксис для описания метаданных.
Хранение метаданных Сборки содержат в себе таблицы метаданных, описанные в спецификации CIL. Таблицы метаданных могут иметь ноль или более записей (вхождений), причем позиция записи определяет её индекс. Когда код CIL использует метаданные, то он делает это по меткам метаданных. Это 32-битное значение, в котором первые 8 бит содержат данные, идентифицирующие соответствующую таблицу метаданных, а оставшиеся 24 бита определяют индекс метаданных в таблице. SDK платформы содержит пример, именуемый metainfo (рус. метаинформация), перечисляющий в виде списка таблицы метаданных в сборке. Однако, эта информация довольно редко используется разработчиком. Метаданные в сборке можно просматривать при помощи утилиты ILDASM (Intermediate Language Disassembler), поставляемой в составе .NET Framework SDK.
Отражение Основная статья: Отражение (программирование) Отражение - это интерфейс программирования приложений (API), используемый для чтения метаданных .NET. API отражения предоставляет возможность реализации в первую очередь логического просмотра метаданных, нежели точный просмотр, обеспечиваемый инструментами типа metainfo. Отражение в версии 1.1 платформы .NET может быть использовано для проверки описания классов и их членов, а также вызова методов. Однако, оно не позволяет среде исполнения получать доступ к CIL ради метода. Версия 2.0 платформы позволяет получать метод из CIL.
Прочие инструменты для работы с метаданными Помимо пространства имён System.Reflection существуют также и другие инструменты, которые могут применяться для работы с метаданными. Microsoft .NET Framework поставляется совместно с библиотекой для манипуляции метаданными CLR, реализуемой в машинном коде. Для извлечения и манипуляции метаданными могут использоваться и сторонние инструменты, такие как PostSharp и Mono Cecil.
Компилятор .NET-языка создает метаданные и сохраняет их в сборку, содержащую CIL. Когда среда CLR исполняет CIL она делает проверку того, что метаданные вызываемого метода совпадают с метаданными, хранящимися в вызывающем методе. Это гарантирует, что метод может быть вызван именно с корректным числом параметров и именно с корректными типами параметров.
Разработчики могут добавлять метаданные в свой код благодаря атрибутам. Существует два типа (две формы) атрибутов: атрибуты, которые определены в среде CLR (т. н. англ. pseudo custom attributes), и пользовательские атрибуты (англ. custom attributes), создаваемые пользователем для добавления в код дополнительных сведений. С точки зрения разработчика оба типа имеют одинаковый синтаксис. Атрибуты в коде являются по сути сообщениями компилятору для создания метаданных. В CIL метаданные (такие как например, модификаторы наследования, модификаторы области видимости), а также почти все, что не является кодом операции или потоками, также помечаются как атрибуты.
Пользовательский атрибут представляет собой обычный класс, наследующий от класса Attribute. Такой атрибут может быть использован для любого метода, свойства, класса или сборки целиком при использовании следующего синтаксиса: [ИмяАтрибута(необязательный параметр, дополнительные пары имя=значение)]. Например:
[Custom(1)]
[Custom(1, Comment="да")]
Пользовательские атрибуты весьма широко используются в платформе .NET Framework. Windows Communication Framework использует атрибуты для определения сервисных контрактов, ASP.NET использует их для предоставления методов как веб-служб, LINQ к SQL использует их для привязки классов к нижележащим реляционным схемам, Visual Studio использует их для группировки свойств объекта, разработчики классов указывают категорию для класса объекта при помощи пользовательского атрибута [Category]. Пользовательские атрибуты обрабатываются кодом приложения, а не CLR. Когда компилятор находит пользовательский атрибут, то он создает пользовательские метаданные, нераспознаваемые средой CLR. Разработчик должен реализовать код для чтения и обработки метаданных. В качестве примера, атрибут, показанный в примере выше, может быть обработан следующим кодом:
{
private int paramNumber = 0;
private string comment = "";
public CustomAttribute() { }
public CustomAttribute(int num) { paramNumber = num; }
public String Comment
{
set { comment = value; }
}
}
Имя класса связано с именем атрибута. Компилятор среды разработки Visual C# автоматически добавляет строку «Attribute» в конец каждого имени атрибута. Как следствие, каждое имя атрибута класса должно оканчиваться такой строкой, но вполне допускается и определение атрибута без суффикса Attribute. При добавлении атрибута к какому-либо элементу компилятор ищет и по указанному имени и имени со словом Attribute на конце, то есть если написать [Custom], то компилятор будет искать и Custom и CustomAttribute. Если же они оба существуют, то компилятор сообщит об ошибке. Во избежание неоднозначности имена атрибутов могут помечаться префиксом «@», в результате чего [@Custom] будет не то же самое что и CustomAttribute. Использование атрибута вызывает конструктор класса, причем поддерживаются и перегруженные конструкторы. Пары «имя-значение» привязываются к свойствам, при этом «имя» обозначает имя свойства, а «значение» — присвоенное значение свойства.
Иногда появляется путаница относительно добавления атрибута. Например, в следующем коде непонятно, что именно обозначается как «orange»:
public int ExampleMethod(string input)
{
//тело метода описывается здесь
}
В данном случае «orange» может означать какой-нибудь тестовый метод ExampleMethod, его возвращаемое значение или всю сборку целиком. В этом случае компилятор по умолчанию попытается обработать атрибут как атрибут метода. Если это не то, что предполагалось автором кода, или автор просто захотел сделать код более понятным, то допускается указание цели атрибута. Написание [return: Orange] укажет на то, что возвращаемым значением будет «апельсин», [assembly: Orange] укажет на всю сборку целиком. Допустимыми целями являются: сборка (assembly), поле (field), событие (event), метод (method), модуль (module), параметр (param), свойство (property), возвращаемое значение (return) и тип (type).
Заранее определённые атрибуты используются так же как и обычные атрибуты, но у них нет настраиваемого обработчика, поскольку компилятор содержит в себе уже встроенное описание таких атрибутов и обрабатывает код в зависимости от установленной метки. Такие атрибуты как Serializable и Obsolete реализуются именно как заранее определённые атрибуты. Заранее определённые атрибуты не должны использоваться ассемблером ILASM, поскольку у него есть собственный синтаксис для описания метаданных.
Сборки содержат в себе таблицы метаданных, описанные в спецификации CIL. Таблицы метаданных могут иметь ноль или более записей (вхождений), причем позиция записи определяет её индекс. Когда код CIL использует метаданные, то он делает это по меткам метаданных. Это 32-битное значение, в котором первые 8 бит содержат данные, идентифицирующие соответствующую таблицу метаданных, а оставшиеся 24 бита определяют индекс метаданных в таблице. SDK платформы содержит пример, именуемый metainfo (рус. метаинформация), перечисляющий в виде списка таблицы метаданных в сборке. Однако, эта информация довольно редко используется разработчиком. Метаданные в сборке можно просматривать при помощи утилиты ILDASM (Intermediate Language Disassembler), поставляемой в составе .NET Framework SDK.
Основная статья: Отражение (программирование)
Отражение - это интерфейс программирования приложений (API), используемый для чтения метаданных .NET. API отражения предоставляет возможность реализации в первую очередь логического просмотра метаданных, нежели точный просмотр, обеспечиваемый инструментами типа metainfo. Отражение в версии 1.1 платформы .NET может быть использовано для проверки описания классов и их членов, а также вызова методов. Однако, оно не позволяет среде исполнения получать доступ к CIL ради метода. Версия 2.0 платформы позволяет получать метод из CIL.
Помимо пространства имён System.Reflection существуют также и другие инструменты, которые могут применяться для работы с метаданными. Microsoft .NET Framework поставляется совместно с библиотекой для манипуляции метаданными CLR, реализуемой в машинном коде. Для извлечения и манипуляции метаданными могут использоваться и сторонние инструменты, такие как PostSharp и Mono Cecil.