使用 Emit 从 int 调用 ToString 时,操作可能会破坏运行时错误
Operation could destabilize the runtime error when invoke ToString from int using 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:操作可能会破坏运行时的稳定性。)
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);
为什么?
使用 Ldarg_0
,您加载参数 0 的值。对于在值类型 T
上调用实例方法,隐式 this
参数没有类型 T
,它的类型是 ref T
,所以你需要加载的不是值,而是参数 0 的引用。Ldarga
指令会为你做这件事。这是眼前的问题。
一个不太严重的问题,虽然对我来说未被发现并且我不是 100% 确定它是否是严格要求的,但你应该是值类型实例方法的 Call
指令,或者在某些特定情况下,Callvirt
指令之前的 Constrained
前缀。
一般情况下,不要猜测你需要什么CIL指令。在 C# 中编写一次您想要的代码,编译它,然后反汇编结果。这会告诉您确切的说明,您可以轻松地看到它的工作原理。
此代码有效
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:操作可能会破坏运行时的稳定性。)
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);
为什么?
使用 Ldarg_0
,您加载参数 0 的值。对于在值类型 T
上调用实例方法,隐式 this
参数没有类型 T
,它的类型是 ref T
,所以你需要加载的不是值,而是参数 0 的引用。Ldarga
指令会为你做这件事。这是眼前的问题。
一个不太严重的问题,虽然对我来说未被发现并且我不是 100% 确定它是否是严格要求的,但你应该是值类型实例方法的 Call
指令,或者在某些特定情况下,Callvirt
指令之前的 Constrained
前缀。
一般情况下,不要猜测你需要什么CIL指令。在 C# 中编写一次您想要的代码,编译它,然后反汇编结果。这会告诉您确切的说明,您可以轻松地看到它的工作原理。