Поделиться через


Соглашения о написании кода для интерфейса API метаданных

В этом разделе обсуждаются соглашения о написании кода, используемые интерфейсом API метаданных.

Обработка строковых параметров

API метаданных представляет все строки в формате Юникод. (Фактически, на диске форматом имен символов является UTF-8, однако он скрыт для клиентов API метаданных.) Каждая возвращенная трока состоит из трех параметров (фактические имена параметров могут отличаться).

  • [in] ULONG cchString — размер буфера (в байтах), в который необходимо возвратить строку, включая символ конца строки NULL.

  • [out] LPCWSTR wzString — указатель на буфер, в который возвращается строка.

  • [out] ULONG *pchString — указатель на размер возвращенной строки (включая символ конца строки NULL). Если буфер слишком мал для хранения в нем полной строки, возвращенная строка усекается, возвращается индикатор ошибки, а клиент может повторно выделить буфер и, при необходимости, повторить попытку.

Имена символов

Следующие соглашения применяются к именам символов для строковых параметров.

  • Строковые параметры, являющиеся именами символов, всегда рассматриваются, как завершающиеся символом конца строки NULL и в параметре длины [in] необходимости нет. Внедренные символы NULL не поддерживаются.

  • Если строка параметра [in] слишком велика для сохранения ее без усечения, возвращается ошибка.

Пользовательские строки

Следующие соглашения применяются к заданным пользователем строковым параметрам.

  • В пользовательские строки могут быть внедрены символы NULL, а символа окончания строки NULL в них быть не должно.

  • Длину следует указывать в параметре cchString. Размер буфера должен в точности совпадать с длиной строки, которая будет в нем храниться.

Хранение значений по умолчанию

Константы могут храниться в метаданных как значения по умолчанию для полей, параметров и свойств. Чтобы задать константу, нужно указать три параметра (фактические имена параметров могут отличаться).

  • [in] DWORD dwCPlusTypeFlag — значение перечисления CorElementType, которое задает тип значения по умолчанию.

  • [in] void const *pValue — указатель на фактическое значение по умолчанию. Например, указатель на 4-разрядное значение типа DWORD, в котором содержится величина 0x0000002A, будет сохранен в метаданных как значение типа DWORD из 42 десятичных символов. Тип значения по умолчанию (заданный в параметре dwCPlusTypeFlag) может быть только примитивом или строкой. Если значение параметра dwCPlusTypeFlag равно ELEMENT_TYPE_CLASS, значение по умолчанию будет равно NULL.

  • [in] ULONG cchValue — количество символов Юникода в последовательности байтов, на которую указывает параметр pValue. Это необходимо, только если в параметре dwCPlusTypeFlag задан тип ELEMENT_TYPE_STRING. Во всех остальных случаях длина определяется типом.

Значения по умолчанию не вставляются автоматически в код инициализации или статически инициализированные области данных. Они просто записываются в метаданные.

Чтобы указать на отсутствие необходимости задавать значение по умолчанию, укажите все биты параметра dwCPlusTypeFlag (то есть, присвойте значение -1).

Указатели NULL для возвращаемых параметров

Поскольку интерфейсы API метаданных выполняют минимальную проверку на наличие ошибок, в следующих случаях возвращаемые им параметры должны быть отличными от NULL указателями.

  • В методах Define отличный от NULL указатель необходим для возвращаемого маркера. Эти методы создают элемент, который необходимо определить, и возвращают для него маркер. Если маркер не нужен, его можно отбросить.

  • Методы Find всегда возвращают маркер для элемента в случае его успешного нахождения.

  • В методе Get значение NULL можно передавать в параметрах, необходимость в возврате которых отсутствует.

  • В методе Set возвращаемое значение обычно отсутствует. Им передается маркер элемента, который необходимо обновить, вместе со значением для обновления, и эти методы выполняют обновление.

Игнорируемые значения параметров

Несколько методов в API метаданных позволяют изменить свойства элемента, определенного ранее. В следующем примере используется метод IMetaDataEmit::SetFieldProps, позволяющий изменить свойства поля, которые были указаны ранее при вызове метода IMetaDataEmit::DefineField.

HRESULT SetFieldProps(mdFieldDef fd, DWORD dwFieldFlags,
        DWORD dwDefType, void const *pValue, ULONG cchValue)

Иногда нужно изменить только значение параметра dwFieldFlags, не меняя значение параметра pValue (или наоборот). В этом случае, чтобы избежать ошибки следует передать значение параметра, даже если это значение должно остаться неизменным. Однако при этом можно передать определенное значение, которое указывает на необходимость игнорировать аргумент, если его значение должно остаться прежним. В интерфейсах API метаданных используются следующие соглашения, позволяющие указать на необходимость игнорировать аргумент метода.

  • Если параметр относится к типу указателя, нужно передать указатель NULL.

  • Если параметр относится к типу значения (обычно это битовая маска флага), нужно передать значение со всеми заданными битами (–1).

Возвраты ошибок

Почти все методы в интерфейсах IMetaDataDispenserEx, IMetaDataEmit и IMetaDataImport для обозначения результатов своего выполнения возвращают значение HRESULT. Если операция выполнена успешно, это значение равно S_OK. Если вызов был неудачным, возвращается другое значение, описывающее причину сбоя, произошедшего при выполнении операции.

Для всех API метаданных используется универсальная схема, предполагающая, что в случае предоставления вызывающим объектом буфера строк, размер которого слишком мал для хранения в нем результатов, интерфейсы API копируют в него максимально возможное количество символов, однако возвращают HRESULT не со значением S_OK, а со значением CLDB_S_TRUNCATION.

Вызывающие объекты интерфейсов IMetadata представляют собой компиляторы или средства. Важно, чтобы эти вызывающие объекты всегда проверяли состояние возврата для каждого вызова с целью обнаружения ошибок. В этих случаях условия возникновения ошибок отражаются проблему на стороне непосредственно вызывающего объекта (например, компилятора), а не на стороне пользователя (например, прикладной программы).

Управление памятью

В универсальной модели COM по умолчанию предполагается, что вызывающий объект освободит память, выделенную вызываемым объектом. Однако методы метаданных работают по другому принципу.

Многие методы метаданных возвращают указатели [out] для блокирования памяти. Память является частью кучи метаданных в модуле и принадлежит среде CLR. Поэтому указатель предоставляется непосредственно во внутреннем хранилище метаданных в памяти среды CLR, и приложению не нужно освобождать память.

Поддержка универсальных шаблонов

В платформе .NET Framework версии 2.0 интерфейсы API метаданных были существенно расширены для обеспечения поддержки универсальных шаблонов (которая также называется параметрическим полиморфизмом). Универсальные шаблоны в чем-то схожи с шаблонами C++. Примером определения универсального класса в C# может служить следующий код:

public class Dictionary<Key, Val> { . . . }

В этом случае класс Dictionary параметризуется двумя универсальными параметрами с именами Key и Val. При создании экземпляров класса пользователь выбирает типы универсальных параметров, как показано в следующем примере:

Dictionary<string, int> NameToPhone = new Dictionary<string, int>();
Dictionary<int, string> PhoneToName = new Dictionary<int, string>();

См. также

Основные понятия

Общие сведения о метаданных