Краткий ответ:
// Call Test method
il.Emit(OpCodes.Ldloc, variable);
il.Emit(OpCodes.Castclass, type);
il.Emit(OpCodes.Call, type.GetMethod("TestMethod"));
Как это сделать? Ну, метод, который я использовал, был Отражатель . Во-первых, напишите метод, который делает то, что вы хотите сделать. Я придумал следующее:
private static object PrecompiledTest()
{
object variable = new TestClass();
((TestClass) variable).TestMethod();
return variable;
}
Теперь, скомпилируйте это, откройте Reflector и откройте вашу сборку. Перейдите к своей функции и посмотрите на MSIL. Вышеприведенная функция декомпилируется в следующее:
.method private hidebysig static object PrecompiledTest() cil managed
{
.maxstack 1
.locals init (
[0] object variable,
[1] object CS$1$0000)
L_0000: nop
L_0001: newobj instance void EmitTest.TestClass::.ctor()
L_0006: stloc.0
L_0007: ldloc.0
L_0008: castclass EmitTest.TestClass
L_000d: callvirt instance void EmitTest.TestClass::TestMethod()
L_0012: nop
L_0013: ldloc.0
L_0014: stloc.1
L_0015: br.s L_0017
L_0017: ldloc.1
L_0018: ret
}
Выше используется callvirt
вместо call
. Я не очень хорошо разбираюсь в IL, поэтому я не уверен в разнице, но call
работает в вашем примере. И последнее, пока мы говорим о Reflector. Вы можете использовать надстройку ReflectionEmitLanguage , чтобы сгенерировать для вас свой код Emit
. Этот плагин генерирует для вас следующий код:
public MethodBuilder BuildMethodPrecompiledTest(TypeBuilder type)
{
// Declaring method builder
// Method attributes
System.Reflection.MethodAttributes methodAttributes =
System.Reflection.MethodAttributes.Private
| System.Reflection.MethodAttributes.HideBySig
| System.Reflection.MethodAttributes.Static;
MethodBuilder method = type.DefineMethod("PrecompiledTest", methodAttributes);
// Preparing Reflection instances
ConstructorInfo ctor1 = typeof(TestClass).GetConstructor(
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
null,
new Type[]{
},
null
);
MethodInfo method2 = typeof(TestClass).GetMethod(
"TestMethod",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
null,
new Type[]{
},
null
);
// Setting return type
method.SetReturnType(typeof(Object));
// Adding parameters
ILGenerator gen = method.GetILGenerator();
// Preparing locals
LocalBuilder variable = gen.DeclareLocal(typeof(Object));
LocalBuilder CS$1$0000 = gen.DeclareLocal(typeof(Object));
// Preparing labels
Label label23 = gen.DefineLabel();
// Writing body
gen.Emit(OpCodes.Nop);
gen.Emit(OpCodes.Newobj,ctor1);
gen.Emit(OpCodes.Stloc_0);
gen.Emit(OpCodes.Ldloc_0);
gen.Emit(OpCodes.Castclass,TestClass);
gen.Emit(OpCodes.Callvirt,method2);
gen.Emit(OpCodes.Nop);
gen.Emit(OpCodes.Ldloc_0);
gen.Emit(OpCodes.Stloc_1);
gen.Emit(OpCodes.Br_S,label23);
gen.MarkLabel(label23);
gen.Emit(OpCodes.Ldloc_1);
gen.Emit(OpCodes.Ret);
// finished
return method;
}