以下代码会产生一个异常,指出它可能会使运行时不稳定。为什么调用指令会导致运行时不稳定?
var method = new DynamicMethod("CallObjectToString", typeof(string),new[]{ typeof(object)});
var ilgen =method.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Call, typeof(object).GetMethod("ToString"));
ilgen.Emit(OpCodes.Ret);
var @delegate = method.CreateDelegate(typeof(Func<object, string>)) as Func<object,string>;
@delegate(new object());
将Opcodes.Call
更改为Opcodes.CallVirt修复了问题。 这一切都很好,但我可以使用typebuilder创建一个动态类型,它具有使用(MethodBuilder)构建的静态方法,它具有相同的IL,并且使用CreateDelegate,并且它不会抛出此异常。实际上,使用方法构建器可以使某个对象完全不同的对象的虚拟方法进行调用,甚至不需要该对象的类型继承。
更令人费解的是,如果我执行诸如new object().ToString()
之类的操作,它还会向IL发出call
指令,而不是callvirt
。
如果使用call
调用虚拟方法是非法的,除非在实例重写中调用基方法的上下文中,那么为什么CLR允许静态地使用不同类型的方法?或者允许call
指令针对已知的非空实体发出?
或者这是通过DynamicMethod
生成的代码的唯一问题?
编辑: 我从性能角度不问,因为我真的不关心它。下面的代码虽然稍微涉及创建一个委托,执行不稳定行动而不破坏运行时。这是整个问题。为什么一个是合法的,另一个是非法的?
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("SomeAssembly"), AssemblyBuilderAccess.Run) ;
var moduleBuilder = assemblyBuilder.DefineDynamicModule("SomeModule");
var typeBuilder = moduleBuilder.DefineType("SomeType");
var methodBuilder = typeBuilder.DefineMethod("SomeStaticMethod",MethodAttributes.Public | MethodAttributes.Static,typeof(string),new[]{typeof(object)});
var ilgen = methodBuilder.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Call, typeof(object).GetMethod("ToString"));
ilgen.Emit(OpCodes.Ret);
var newType = typeBuilder.CreateType();
var @delegate = Delegate.CreateDelegate(typeof(Func<object, string>),newType.GetMethod("SomeStaticMethod")) as Func<object,string>;
@delegate(new object());
这是真的,但为什么它允许在代码中,我通过与typebuilder反射发射生成的代码。它实际上并没有调用对象的重载,但实际上是直接调用的。 – 2010-11-20 20:47:47
我只能说,看来Reflection.Emit假设你知道你在做什么。我不明白这里直接的电话会不会以任何严肃的方式破坏运行时间,但看起来DynamicMethod首先试图保护你。这很难确定。 – Stewart 2010-11-20 20:53:09