使用 Reflection.Emit 的奇怪参数序列
我最近一直在研究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。
干杯
罗汉
I have been looking at Reflection.Emit recently. I wrote a simple program that generates a DynamicMethod which simple calls another method with the same parameters
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);
}
}
When i run this example it i would expect it to output 1,2,3,4,5,6 however, it outputs 2,3,4,5,6,1
I'm not too sure why... If you guys know of any good resources for using Reflection.Emit could you point me in that direction. I have been using Reflector with the Emit AddIn.
Cheers
Rohan
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您遇到的问题是您正在调用动态方法,而不是静态方法。 您生成的方法没有对 Program 类的实例的引用。
另请注意,对于 6 参数方法,您将 7 个参数压入堆栈。
第一个参数应该是对您调用该方法的对象的引用。
您看到的奇怪行为可能是由于没有索引 6 的参数,并且它回绕到参数数组的开头。
请参阅 VS 帮助中的“如何:定义和执行动态方法”。
您可以通过在方法调用中接受对象参数或将其设置为静态来使其工作:
public delegate void TestHandler(object instance, int a, int b, int c, int d, int e, int f);
The problem you are having is that you are invoking a dynamic method, not a static one. Your generated method does not have a reference to the the instance of the Program class.
Also note you are pushing 7 parameters onto the stack for a 6 parameter method.
The first parameter should be a reference to the object you are invoking the method on.
The weird behavior you are seeing might be due to there not being a parameter of index 6, and it wrapping around back to the start of the parameter array.
See "How to: Define and Execute Dynamic Methods" in the VS help.
You can get it working by accepting a object parameter on in your method call, or making it static:
public delegate void TestHandler(object instance, int a, int b, int c, int d, int e, int f);
要使其工作,您应该
Question
设为static
方法gen.Emit(OpCodes.Ldarg_S,6);
MethodInfo method1 = ...
相应的一个“气味”是,在
Question
方法上停止调试时,您无法评估this
引用。 这不应该用于实例方法...;-)编辑:Ops。 我刚刚看到罗伯特·瓦格纳的回答,它比我的解释得更好。 如果需要的话,准备取消我的帖子......:-)
To make it work you should
Question
astatic
methodgen.Emit(OpCodes.Ldarg_S,6);
MethodInfo method1 = ...
accordinglyOne "smell" is that stopping in debug on the
Question
method you can't evaluate thethis
reference. And this should not be for an instance method... ;-)Edit: Ops. I have just seen the answer from Robert Wagner which is much better explained than mine. Ready to cancel my post if needed... :-)