为啥这个 DynamicMethod (ldarg.1, newobj, ret) 会触发 VerificationException?

Posted

技术标签:

【中文标题】为啥这个 DynamicMethod (ldarg.1, newobj, ret) 会触发 VerificationException?【英文标题】:Why does this DynamicMethod (ldarg.1, newobj, ret) trigger a VerificationException?为什么这个 DynamicMethod (ldarg.1, newobj, ret) 会触发 VerificationException? 【发布时间】:2012-08-20 16:29:22 【问题描述】:

我有一个将构造函数包装在动态工厂方法中的方法:

static Func<TArg1, TResult> ToFactoryMethod<TArg1, TResult>(this ConstructorInfo ctor)
    where TResult : class

    var factoryMethod = new DynamicMethod(
         name:           string.Format("_0:N", Guid.NewGuid()),
         returnType:     typeof(TResult), 
         parameterTypes: new Type[]  typeof(TArg1) );

    ILGenerator il = factoryMethod.GetILGenerator();
    il.Emit(OpCodes.Ldarg_1);
    il.Emit(OpCodes.Newobj, ctor);
    il.Emit(OpCodes.Ret);

    return (Func<TArg1, TResult>)
         factoryMethod.CreateDelegate(typeof(Func<TArg1, TResult>));

但是,以下代码会在 .Invoke(…) 上抛出 VerificationException

ConstructorInfo ctor = typeof(Uri).GetConstructor(new Type[]  typeof(string) );
Func<string, Uri> uriFactory = ctor.ToFactoryMethod<string, Uri>();
Uri uri = uriFactory.Invoke("http://www.example.com");

如果我替换ldarg.1,则不会引发异常; newobj &lt;ctor&gt;ldnull,所以问题肯定是这两条IL指令引起的。进一步的实验表明错误在于ldarg.1。 (对于上面的具体示例,我已将其替换为 ldstr &lt;string&gt;。)

有人看到这些 IL 指令有什么问题吗?

【问题讨论】:

您的动态方法似乎只有一个参数,并且是静态的。你为什么使用Ldarg_1 而不是Ldarg_0?由于没有“this”参数(通常是 0 arg),因此您应该使用 Ldarg_0。 我现在在问自己。愚蠢的我,我想我假设索引 0 处的参数总是为this 对象引用保留,即使使用静态方法也是如此。当然,事实并非如此。 【参考方案1】:

这个方法是静态的,所以它没有this 参数作为arg0。将il.Emit(OpCodes.Ldarg_1); 更改为il.Emit(OpCodes.Ldarg_0); 对我来说效果很好。

【讨论】:

感谢您指出显而易见的事情!我一直在寻找一些非常复杂的错误原因,但不是为了这个...... :-O

以上是关于为啥这个 DynamicMethod (ldarg.1, newobj, ret) 会触发 VerificationException?的主要内容,如果未能解决你的问题,请参考以下文章

将 lambda 作为 IL 流传递给辅助 AppDomain 并使用 DynamicMethod 将其组装回来

“ [轻量功能]在调用堆栈中

在 Windows CE 中创建对象实例比反射更快

学习 CIL (MSIL) 的最佳资源是啥

动态IL织入框架Harmony简单入手

反射_IsDefined判断方法上有自定义的标签