Создайте экземпляр типа с помощью Emit (Opcodes.Call, methodinfo)

Я использую Reflection и ilGenerator для создания .Exe, который вызывает метод из DLL.

Моя проблема в том, что когда это метод экземпляра, я должен поместить экземпляр в стек перед вызовом метода. Поэтому у меня есть метод на С#, который создает и возвращает этот экземпляр. Он бросает System.MethodAccessException.

Мой вопрос в том, возможно ли это вообще? Как это работает? Делая это в IL, il.Emit(Opcodes.call, methodInfo), в вызове, который создает .exe, во время выполнения, как он узнает, какой метод вызывать? Идет ли метод, который я хочу вызвать, в сборку .exe? Я очень смущен этим.

Я иду в DLL, получаю тип, получаю MethodInfo, который я хочу вызвать. Я создаю новый Assembly->AssemblyBuilder->ModuleBuilder->TypeBuilder. Этот новый тип, который я создаю, расширяет Type из DLL:

 TypeBuilder tb = mb.DefineType("TypeApp" + typeName, baseType.Attributes, DLLType);

Я создаю MethodBuilder как точку входа нового типа:

MethodBuilder metb = tb.DefineMethod("Main", MethodAttributes.Public |
            MethodAttributes.Static, typeof(void), argsArray);
ab.SetEntryPoint(metb);

Затем я генерирую IL для метода Main:

ILGenerator il = metb.GetILGenerator();

il.Emit(OpCodes.Call, callcreateInstanceMethodInfo);

Ил продолжается, но я пока не до конца в этом разбираюсь...

Затем я создаю .exe

 tb.CreateType();
 ab.Save(typeName + methodName + ".exe");

person Franmcod    schedule 28.10.2015    source источник
comment
Downvoters: пожалуйста, прокомментируйте.   -  person Martin Mulder    schedule 28.10.2015
comment
Можете ли вы показать, что вы делаете, чтобы получить MethodAccessException? Мне трудно следить за описанием в вопросе.   -  person Jon Hanna    schedule 28.10.2015
comment
да, минусуйте сколько хотите, но хотя бы скажите почему, сейчас буду редактировать   -  person Franmcod    schedule 28.10.2015
comment
Создайте высокоуровневый код для своей задачи, скомпилируйте его, а затем просмотрите сгенерированный IL с помощью таких инструментов, как Ильдасм.   -  person thehennyy    schedule 28.10.2015


Ответы (1)


Он бросает System.MethodAccessException.

Вы пытаетесь вызвать метод, который обычно невидим для создаваемого вами типа (вызов частного или внутреннего метода, вызов защищенного метода в классе, от которого вы не наследуете). Я считаю, что это возможно, отключив проверку, но это увеличивает требования к безопасности кода, что является проблемой, если вам нужно работать в среде с частичным доверием.

в вызове, который создает .exe, во время выполнения, как он узнает, какой метод вызывать?

Выпущенный IL содержит 4-байтовый токен метаданных, по сути, это ссылка на запись в одной из таблиц метаданных в сгенерированном модуле (либо в таблице MethodDef, либо в таблице MemberRef). Если это токен MethodDef, то это прямая ссылка на определение методов, если это токен MemberRef, то он предоставит достаточно информации для определения правильной сборки/класса/метода для вызова.

Код, который вы показываете для создания IL, указывает на то, что вы используете код операции вызова. Если вы вызываете виртуальный метод, вам следует вместо этого использовать callvirt (хотя вы можете использовать вызов для неабстрактных методов, это приведет к вызову конкретной реализации... даже если она была переопределена, это может быть неожиданно, и я читал где-то были добавлены требования безопасности для использования вызова виртуального метода другого объекта).

person Brian Reichle    schedule 28.10.2015