Некоторая предварительная информация
С учетом следующей функции C #:
public static void func<T>(T t)
{
System.Console.WriteLine(t);
}
Он компилируется в следующий CIL:
.method public hidebysig static void func<T>(!!T t) cil managed
{
ldarg.0
box !!T
call void [mscorlib]System.Console::WriteLine(object)
ret
}
Сигнатура вышеприведенного метода: 10 01 01 01 1E 00
, где:
10 - Calling convention (IMAGE_CEE_CS_CALLCONV_GENERIC)
01 - Function generic arguments count (which is 1)
01 - Function arguments count (which is 1)
01 - Return type (ELEMENT_TYPE_VOID)
1E - First argument type (ELEMENT_TYPE_MVAR)
00 - Index of above MVAR (which is 0)
Также см. Следующую инструкцию с действительным байтовым кодом:
box !!T - 8C 1B000001
1B000001
указывает на первую запись втаблица TypeSpec, которая указывает на BLOB-объект 02 1E 00
, где:
02 - Blob length
1E - Type type (ELEMENT_TYPE_MVAR)
00 - Index of above MVAR (which is 0)
Как мы видим, сигнатура метода содержит обобщенный аргумент описательным образом, где мы имеем фактическую сигнатуру типа.
Однако при использовании OpCode, который требует TypeDef / Ref / Spec, предоставляется TypeSpec, и TypeSpec указывает на подпись с информацией о типе.
Так что мой вопрос:
Я пишу профилировщик, который выполняет некоторую перезапись IL, и, учитывая сигнатуру функции, я хотел бы добавить несколько OpCodes в тело функции, которые будут работать с аргументами.
ИспользованиеIMetaDataImport2
интерфейс, как можетn Я получаю токен TypeSpec, который мне понадобится для заданного универсального параметра?
Я могу видеть 2 варианта:
- Перебирать EnumTypeSpecs до тех пор, пока не найду сигнатуру, соответствующую
- Использование интерфейса
IMetaDataEmit
для создания новой TypeSpec
Однако по понятным причинам я бы хотел избежать этих двух вариантов и выбрать более разумную альтернативу.