我最近一直在关注Reflection.Emit.我写了一个简单的程序,它生成一个DynamicMethod,它简单地调用另一个具有相同参数的方法
class Program { static void Main(string[] args) { Program p = new Program(); p.Test(); } public delegate void TestHandler(int a, int b, int c, int d, int e, int f); public void Test() { DynamicMethod method = new DynamicMethod(string.Empty, typeof(void), new[] { typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32) }, typeof(Program)); MethodInfo method1 = typeof(Program).GetMethod("Question",BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,null,new Type[]{typeof(Int32),typeof(Int32),typeof(Int32),typeof(Int32),typeof(Int32),typeof(Int32)},null); MethodInfo method2 = typeof(MethodBase).GetMethod("GetCurrentMethod", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { }, null); MethodInfo method3 = typeof(Console).GetMethod("WriteLine", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(Object) }, null); ILGenerator gen = method.GetILGenerator(); gen.Emit(OpCodes.Nop); gen.Emit(OpCodes.Ldarg_S, 0); gen.Emit(OpCodes.Ldarg_S, 1); gen.Emit(OpCodes.Ldarg_S, 2); gen.Emit(OpCodes.Ldarg_S, 3); gen.Emit(OpCodes.Ldarg_S, 4); gen.Emit(OpCodes.Ldarg_S, 5); gen.Emit(OpCodes.Ldarg_S, 6); gen.Emit(OpCodes.Call, method1); gen.Emit(OpCodes.Nop); gen.Emit(OpCodes.Call, method2); gen.Emit(OpCodes.Call, method3); gen.Emit(OpCodes.Nop); gen.Emit(OpCodes.Ret); TestHandler handler = method.CreateDelegate(typeof(TestHandler)) as TestHandler; handler(1, 2, 3, 4, 5, 6); } public void Question(int a, int b, int c, int d, int e, int f) { Console.WriteLine("{0},{1},{2},{3},{4},{5}", a, b, c, d, e, f); } }
当我运行这个例子时,我希望它输出1,2,3,4,5,6然而,它输出2,3,4,5,6,1
我不太清楚为什么......如果你们知道使用Reflection.Emit的任何好资源你能指出我的方向吗?我一直在使用Reflector和Emit AddIn.
干杯
罗汉
您遇到的问题是您正在调用动态方法,而不是静态方法.您生成的方法没有对Program类实例的引用.
另请注意,您正在将7个参数推入堆栈以获得6参数方法.第一个参数应该是对要调用方法的对象的引用.
您看到的奇怪行为可能是由于没有索引6的参数,并且它回绕到参数数组的开头.
请参阅VS帮助中的"如何:定义和执行动态方法".
您可以通过在方法调用中接受对象参数或将其设置为静态来使其工作:
public delegate void TestHandler(object instance,int a,int b,int c,int d,int e,int f);
public void Test() { DynamicMethod method = new DynamicMethod(string.Empty, typeof(void), new[] { typeof(object), typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32) }, typeof(Program)); MethodInfo method1 = typeof(Program).GetMethod("Question", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32) }, null); MethodInfo method2 = typeof(MethodBase).GetMethod("GetCurrentMethod", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { }, null); MethodInfo method3 = typeof(Console).GetMethod("WriteLine", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(Object) }, null); ILGenerator gen = method.GetILGenerator(); gen.Emit(OpCodes.Nop); gen.Emit(OpCodes.Ldarg_S, 0); gen.Emit(OpCodes.Ldarg_S, 1); gen.Emit(OpCodes.Ldarg_S, 2); gen.Emit(OpCodes.Ldarg_S, 3); gen.Emit(OpCodes.Ldarg_S, 4); gen.Emit(OpCodes.Ldarg_S, 5); gen.Emit(OpCodes.Ldarg_S, 6); gen.Emit(OpCodes.Call, method1); gen.Emit(OpCodes.Nop); gen.Emit(OpCodes.Call, method2); gen.Emit(OpCodes.Call, method3); gen.Emit(OpCodes.Nop); gen.Emit(OpCodes.Ret); TestHandler handler = method.CreateDelegate(typeof(TestHandler)) as TestHandler; handler(this, 1, 2, 3, 4, 5, 6); } public void Question(int a, int b, int c, int d, int e, int f) { Console.WriteLine("{0},{1},{2},{3},{4},{5}", a, b, c, d, e, f); }