Создан неверный код IL
Я пытаюсь объединить два метода вместе (один метод из моего проекта, один из DLL) и записать их в DLL. Исходный код выглядит так:
.method public hidebysig static class Storage.DataMap
Create() cil managed
{
.maxstack 8
// [22 7 - 22 70]
IL_0000: call unmanaged stdcall native int Storage.DataMapPlugin::DataMap_CreateEmptyDataMap()
IL_0005: newobj instance void Storage.DataMap::.ctor(native int)
IL_000a: ret
} // end of method DataMap::Create
Я хочу добавить простой Console.WriteLine к этому коду, в итоге я получаю следующее: (из декомпилятора)
.method public hidebysig static class Storage.DataMap
Create() cil managed
{
.maxstack 8
// [22 7 - 22 44]
IL_0000: ldstr "Hello World"
IL_0005: call void [mscorlib]System.Console::WriteLine(string)
// [23 7 - 23 70]
IL_000a: call unmanaged stdcall native int Storage.DataMapPlugin::DataMap_CreateEmptyDataMap()
IL_000f: newobj instance void Storage.DataMap::.ctor(native int)
IL_0014: ret
} // end of method DataMap::Create
Мой декомпилятор не может декомпилировать это (dotPeek), поэтому я предполагаю, что сгенерированный мной IL недействителен. Тем не менее, я не уверен, что не так с моим сгенерированным IL.
я использую dnlib
с помощью C# для получения кода IL обоих методов, а затем Concat обоих блоков кода вместе (я удалил nop
а также ret
заявления (за исключением последнего)). Для перекомпиляции кода я использую ModuleDef#Write(String)
функция, у меня был успех с этим при написании моих собственных операторов IL, но не при объединении уже существующих операторов.
(Следующий IL напечатан с консоли, а не с декомпилятора)
Оригинальная часть 1 ИЛ:
IL_0000: nop
IL_0001: ldstr "Hello World"
IL_0006: call System.Void System.Console::WriteLine(System.String)
IL_000B: nop
IL_000C: ret
Оригинальная часть 2 ИЛ:
IL_0000: call System.IntPtr Storage.DataMapPlugin::DataMap_CreateEmptyDataMap()
IL_0005: newobj System.Void Storage.DataMap::.ctor(System.IntPtr)
IL_000A: ret
Слитый ИЛ:
IL_0001: ldstr "Hello World"
IL_0006: call System.Void System.Console::WriteLine(System.String)
IL_0000: call System.IntPtr Storage.DataMapPlugin::DataMap_CreateEmptyDataMap()
IL_0005: newobj System.Void Storage.DataMap::.ctor(System.IntPtr)
IL_000A: ret
1 ответ
Я исправил свою проблему. Как несколько человек правильно указали в комментариях, IL является правильным. Проблема связана не с моим кодом или сгенерированным IL, а с декомпилятором dotPeek.
Произошло следующее: я впервые сгенерировал DLL, но IL был неправильным (у него было 2 оператора return), декомпилировал его с помощью dotPeek и увидел, что IL был искажен. Я сделал это снова, но с правильным IL (только 1 оператор возврата) и удалил старую DLL, переименовал новую DLL в старую, удалил одну. Однако DotPeek это не понравилось, он показал бы мне обновленный IL, но не обновленный код.
После многих перезапусков и удаления / повторного добавления сборки я обнаружил, что это так. dnSpy, кажется, работает намного лучше, чем dotPeek, поэтому я буду использовать это в будущем.