Формат файла .NET – внутреннее устройство сигнатур (часть 1) - MethodDefSig
ОГЛАВЛЕНИЕ
4.3 MethodDefSig
Данная сигнатура хранит информацию, связанную с методами, определенными в текущей сборке, такую как тип соглашения о вызовах, количество обобщенных параметров, количество нормальных параметров метода, тип возвращаемой переменной и тип каждого параметра, переданного методу. Она индексируется столбцом MethodDef.Signature.
Рисунок 6. Схема синтаксиса сигнатуры MethodDefSig
Дополнительно используются несколько флагов (перечислены в таблице ниже), они объединяются с помощью OR и размещаются во втором байте сигнатуры (первый байт – размер сигнатуры).
Имя |
Значение |
Что означает |
HASTHIS |
0x20 |
Первый передаваемый методу аргумент - указатель this, этот флаг установлен, когда метод – экземпляр или виртуальный. Вы также можете прочитать объяснение флага HASTHIS в предыдущем подразделе |
EXPLICITTHIS |
0x40 |
Спецификация гласит: "Обычно список параметров (всегда сопровождающий соглашение о вызовах) не предоставляет информацию о типе указателя this, так как его можно получить из другой информации. Когда явный экземпляр комбинации задан, все же, первый тип в последующем списке параметров задает тип указателя this, а следующие элементы задают типы самих параметров". Заметьте, что если EXPLICITTHIS установлен, HASTHIS тоже должен быть установлен. |
DEFAULT |
0x00 |
Позволяет общеязыковой среде исполнения определить соглашение о вызовах, этот флаг установлен при вызове статических методов. |
VARARG |
0x05 |
Задает соглашение о вызовах для методов с изменяющимися аргументами. |
GENERIC |
0x10 |
Метод имеет один или больше обобщенных параметров. |
Пример 1
Как водится, начнем с простого примера: на этот раз мы создали метод экземпляра, имеющий два обобщенных параметра и два нормальных параметра, для упрощения метод не имеет никакого тела.
// Полный исходник: MethodDefSig\1.cs
// Бинарный файл: MethodDefSig\1.dll
// (...)
public void TestMethod<GenArg1, GenArg2>(int Param1, object Param2) { }
Сигнатура MethodDefSig для примера метода хранится в смещении 0x000A и выглядит так.
Смещение |
Значение |
Что означает |
0x0A |
0x06 |
Размер сигнатуры |
0x0B |
0x30 |
Так как это экземпляр и обобщенный метод, флаги HASTHIS и GENERIC установлены, 0x20 OR 0x10 = 0x30. |
0x0C |
0x02 |
Количество обобщенных параметров. |
0x0D |
0x02 |
Количество нормальных параметров. |
0x0E |
0x01 |
Тип возвращаемого значения (void), смотрите константы. |
0x0F |
0x08 |
Тип первого параметра (int32), смотрите константы. |
0x10 |
0x1C |
Тип второго параметра (object), смотрите константы. |
Пример 2
В данном примере снова показано использование флага HASTHIS, определение рассматриваемого метода выглядит так.
// Полный исходник: MethodDefSig\2.cs
// Двоичный файл: MethodDefSig\2.dll
// (...)
public class TestClas
{
public static void TestMethod(int Param1, object Param2) { }
}
Сигнатура снова хранится в 0x000A в куче #Blob и выглядит так.
Смещение |
Значение |
Что означает |
0x0A |
0x05 |
Размер сигнатуры |
0x0B |
0x00 |
Есть один установленный флаг, а именно DEFAULT – это означает, что метод статический, и позволяет CLR определить используемое соглашение о вызовах. Метод не обобщенный, так как флаг GENERIC не установлен, следовательно, следующий байт задает количество нормальных (не обобщенных) параметров, передаваемых методу. |
0x0C |
0x02 |
Количество нормальных параметров. |
0x0D |
0x01 |
Тип возвращаемого значения (void), смотрите константы. |
0x0E |
0x08 |
Тип первого параметра (int32), смотрите константы. |
0x0F |
0x1C |
Тип второго параметра (object), смотрите константы. |
Пример 3
Теперь посмотрим, как работает флаг EXPLICITTHIS: его можно включить путем использования ключевого слова explicit в определении метода, разумеется, на языке CIL.
// Полный исходник: MethodDefSig\3.il
// двоичный файл: MethodDefSig\3.dll
// (...)
.method instance explicit void TestMethod () cil managed
{
.maxstack 2
ret
}
MethodDefSig для вышеуказанного метода выглядит так.
Смещение |
Значение |
Что означает |
0x01 |
0x03 |
Размер сигнатуры |
0x02 |
0x60 |
Флаги HASTHIS и EXPLICITTHIS установлены, так как 0x20 OR 0x40 = 0x60. |
0x03 |
0x00 |
Количество параметров, принимаемых методом. |
0x04 |
0x01 |
Тип возвращаемого значения (void), смотрите константы. |
Пример 4
В этом примере был создан метод, принимающий изменяемые аргументы, т.е. кроме нормальных параметров, заданных в объявлении, он принимает переменное количество параметров изменяемого типа. Добавление vararg в ключевое слово языка CIL в определение метода заставляет метод принимать изменяемые аргументы, что видно по листингу кода ниже.
Важно: Использование ключевого слова params в C# не устанавливает флаг VARARG в связанной с методом сигнатуре. Метод, использующий ключевое слово params в C#, всего лишь оформляется компилятором C# атрибутом ParamArray, и дополнительные параметры рассматриваются как нормальный массив. Можно сделать метод истинно VARARG в C#, следуя данной инструкции, но это не совместимо с CLS.
// Полный исходник: MethodDefSig\4.il
// Двоичный файл: MethodDefSig\4.dll
// (...)
.method instance vararg void TestMethod () cil managed
{
.maxstack 2
ret
}
Сигнатура метода рассмотрена в следующей таблице.
Смещение |
Значение |
Что означает |
0x01 |
0x03 |
Размер сигнатуры |
0x02 |
0x25 |
Метод является экземпляром и принимает изменяемые аргументы, следовательно, флаги HASTHIS и VARARG установлены, и 0x20 OR 0x05 = 0x25 |
0x03 |
0x00 |
Количество параметров, принимаемых методом. |
0x04 |
0x01 |
Тип возвращаемого значения (void), смотрите константы. |