Изменение кода IL, вызывающее исключение InvalidProgramException во время выполнения
Я пытаюсь удалить подписку на событие Tick в IL Code, чтобы оно никогда не срабатывало.
Вот код IL:
IL_0e19: ldftn instance void App.Framework.MainForm::mTimer_Tick(object, class [mscorlib]System.EventArgs)
IL_0e1f: newobj instance void [mscorlib]System.EventHandler::.ctor(object, native int)
IL_0e24: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Timer::add_Tick(class [mscorlib]System.EventHandler)
IL_0e29: ldarg.0
Так что я подумал, что я должен иметь возможность удалить последние 2 строки, чтобы удалить подписку, и все должно быть в порядке.
IL_0e24: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Timer::add_Tick(class [mscorlib]System.EventHandler)
IL_0e29: ldarg.0
Я успешно компилирую код IL с помощью:
ilasm.exe c:\Framework.il /32bitpreferred /dll
Теперь, когда я пытаюсь запустить программу, она выдает исключение:
System.InvalidProgramException: JIT Compiler encountered an internal limitation.
Если я скомпилирую IL без каких-либо модификаций, то программа запускается без каких-либо исключений, поэтому изменения вносятся.
1 ответ
ldarg0
не связан и предположительно относится к следующей операции; так что вы не должны бросать это. Вы также оставили что-то в стеке, поэтому вместо того, чтобы просто удалить callvirt, вы должны вместо этого вывести два значения - целевой экземпляр (загрузка не показана) и экземпляр обработчика события (из ldftn
/ newobj
- обратите внимание, что есть также не показанная загрузка, которая относится к этому шагу). Или в качестве альтернативы - не загружайте эти два значения в первую очередь. Вероятно, довольно много вещей происходит раньше IL_0e19
это может сделать с некоторой очисткой.
В основном, такой код:
someTimer.Tick += target.SomeMethod;
это:
- загрузить someTimer [стек теперь someTimer]
- загрузить цель [стек теперь someTimer, цель]
- загрузить SomeMethod в качестве указателя на функцию [стек теперь someTimer, target, указатель на функцию]
- создать делегата для этого объекта / указателя [стек теперь someTimer, делегат]
- виртуальный вызов метода Tick_add [стек теперь пуст]
IL, который вы показываете, начинается с "загрузить SomeMethod как указатель на функцию" и включает несвязанную загрузку для следующей операции.