To call DoClass
您需要提供参数的方法,只需Call classMethod
是行不通的。
第一个参数当然是“this”引用:
genIM.Emit(OpCodes.Ldarg_0);
第二个参数是对象数组。params
是编译器功能,如果您自己构建代码 - 您必须将其视为params
不在这里。我的意思是 - 虽然
DoClass();
当你用代码编写它时是合法的 - 编译为:
DoClass(new object[0]);
因此,当您发出此调用时 - 您应该始终提供对象数组参数,不能省略它。
将对象数组压入堆栈:
// push array length (0, for example) to stack
genIM.Emit(OpCodes.Ldc_I4_0);
// push new array with length given by the above value (0)
genIM.Emit(OpCodes.Newarr, typeof(object));
此时您的代码将编译并运行良好。这类似于:
public class GeneratedA : A, IA
{
public void DoInterface(string arg0, bool arg1, int arg2, object arg3, List<float> arg4, params object[] otherArgs)
{
DoClass();
}
}
如果你想传递所有参数DoInterface
,这需要更多的工作。我将提供几个例子。传递第一个参数 (string arg0
):
genIM.Emit(OpCodes.Dup);
// push index to store next element at (0)
genIM.Emit(OpCodes.Ldc_I4_0);
// push first argument (arg0 of DoInterface) to stack
genIM.Emit(OpCodes.Ldarg_1);
// store element in array at given index (yourArguments[0] = arg0)
genIM.Emit(OpCodes.Stelem_Ref);
传递第二个参数:
genIM.Emit(OpCodes.Dup);
// push index to store next element at (1)
genIM.Emit(OpCodes.Ldc_I4_1);
// push arg2
genIM.Emit(OpCodes.Ldarg_2);
// box, because boolean is value type, and you store it in object array
genIM.Emit(OpCodes.Box, typeof(bool));
// store in array (yourArguments[1] = (object) arg2
genIM.Emit(OpCodes.Stelem_Ref);
等等。
当您将参数推入数组时,不要忘记更改其长度以反映参数的数量:
// push array length - 6
genIM.Emit(OpCodes.Ldc_I4_6);
// push new array with length given by the above value (6)
genIM.Emit(OpCodes.Newarr, typeof(object));
另请注意,您可能想要更改:
TypeBuilder tb = mb.DefineType("GeneratedA", TypeAttributes.Public, baseType);
to
TypeBuilder tb = mb.DefineType("GeneratedA", TypeAttributes.Public, classType);
或者只是更改为baseType = typeof(A)
,因为您想继承生成的类A
,不是来自object
.
使用前 2 个参数发出调用的完整代码:
ILGenerator genIM = mbIM.GetILGenerator();
genIM.Emit(OpCodes.Ldarg_0);
genIM.Emit(OpCodes.Ldc_I4_2);
genIM.Emit(OpCodes.Newarr, typeof(object));
genIM.Emit(OpCodes.Dup);
genIM.Emit(OpCodes.Ldc_I4_0);
genIM.Emit(OpCodes.Ldarg_1);
genIM.Emit(OpCodes.Stelem_Ref);
genIM.Emit(OpCodes.Dup);
genIM.Emit(OpCodes.Ldc_I4_1);
genIM.Emit(OpCodes.Ldarg_2);
genIM.Emit(OpCodes.Box, typeof(bool));
genIM.Emit(OpCodes.Stelem_Ref);
genIM.Emit(OpCodes.Call, classMethod);
genIM.Emit(OpCodes.Ret);