Как передать IL для вызова DynamicMethod при создании DynamicMethod?
При вызове ILGenerator.Emit(OpCodes.Callvirt, myDynamicMethod); IL, который выдает результат MissingMethodException при выполнении.
Я воспроизвел проблему с этим минимальным кодом:
var dm1 = new DynamicMethod("Dm1", typeof(void), new Type[0]);
dm1.GetILGenerator().Emit(OpCodes.Ret);
var dm2 = new DynamicMethod("Dm2", typeof(void), new Type[0]);
var ilGenerator = dm2.GetILGenerator();
ilGenerator.Emit(OpCodes.Callvirt, dm1);
ilGenerator.Emit(OpCodes.Ret);
dm2.Invoke(null, new Type[0]); // exception raised here





Вы действительно можете вызвать DynamicMethod из другого DynamicMethod.
var ilGenerator = dm2.GetILGenerator();
ilGenerator.Emit(OpCodes.Call, dm1);
OpCodes.Callvirt следует использовать при вызове виртуального метода объекта (например, ToString()). Это не относится к DynamicMethod.
Вместо этого следует использовать OpCodes.Call.
Из того, что я понял из других ошибок, DynamicMethods может быть только статикой, верно? Я копирую свой IL из существующего метода и заменяю вызовы методов динамическими, что означает, что вместо вызова string.GetHashCode() (например) он вызывает динамический GetHashCode(string). Исходя из моего базового понимания IL, 2 должны быть эквивалентны (т.е. просто вопрос замены инструкции вызова, а остальное должно просто работать).
@Sellorio Я запускаю код в Visual Studio 2017 и не получаю ошибки. попробуй сменить ctor на new DynamicMethod("Dm1", typeof(void), new Type[0], typeof(object), true);
Да, базовый код работает, но мой основной код еще не работает. (см предыдущий комментарий)
Правильно, это только статика. Единственный способ добавить методы экземпляра во время выполнения — это использовать System.Reflection.Emit.TypeBuilder, а не существующие типы. Вы можете заставить свой DynamicMethod имитировать метод экземпляра, если первый параметр будет этого типа. Однако это никак нельзя назвать виртуально
Да, я так и думал. Если я правильно понимаю, string.GetHashCode() можно тривиально заменить на GetHashCode(string) (динамический), а IL, окружающий вызов, идентичен (поскольку param0 используется для this в вызовах экземпляра и param0 для статических вызовов... верно?)
Да, это точно. Ldarg0 будет использоваться для this экземпляра и первого параметра статического
Тогда я не знаю, что происходит. У меня есть ветка с моими изменениями, если хотите проверить: github.com/Sellorio/JazSharp/tree/switch-to-reflection-emit
Помещаете ли вы аргумент(ы) в стек перед инструкцией Call?
Эй, извините, я потратил на это слишком много часов подряд. Звонок работает. Проблема заключается в коде внутри метода, поэтому не беспокойтесь об этом. Спасибо за вашу помощь!
К вашему сведению, забыл указать тип при использовании Newarr OpCode во втором динамическом методе.
Теперь получаю исключение Invalid Program.