使用Emit从int调用ToString时,操作可能会破坏运行时错误

时间:2016-05-04 19:57:02

标签: c# reflection reflection.emit

此代码有效

var toString = typeof(string).GetMethod("ToString", new Type[] { });

var dm = new DynamicMethod("MyToString", typeof(string), new Type[] { typeof(string) });

var il = dm.GetILGenerator();

il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Callvirt, toString);
il.Emit(OpCodes.Ret);

Delegate d = dm.CreateDelegate(typeof(Func<string, string>));

var r = d.DynamicInvoke("10");

此代码抛出异常(System.Security.VerificationException:Operation可能会破坏运行时的稳定性。)

var toString = typeof(int).GetMethod("ToString", new Type[] { });

var dm = new DynamicMethod("MyToString", typeof(string), new Type[] { typeof(int) });

var il = dm.GetILGenerator();

il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Callvirt, toString);
il.Emit(OpCodes.Ret);

Delegate d = dm.CreateDelegate(typeof(Func<int, string>));

var r = d.DynamicInvoke(10);

为什么?

1 个答案:

答案 0 :(得分:9)

使用Ldarg_0,您可以加载参数0的值。对于在值类型T上调用实例方法,隐式this参数没有类型T ,它具有类型ref T,因此您需要加载不是值,而是加载对参数0的引用。Ldarga指令将为您执行此操作。这是当前的问题。

一个不那么严重的问题,虽然对我来说未被发现并且我不是100%确定是否严格要求,但是你应该是关于值类型的实例方法的Call指令,或者某些特定情况,Constrained指令前的Callvirt前缀。

一般情况下,不要猜测您需要什么CIL指令。在C#中编写您想要的代码一次,编译它,并反汇编结果。这会告诉您可以轻松查看的确切说明。