动态方法和输出参数?

9

我如何定义一个带有out参数的委托的DynamicMethod,就像这样?

public delegate void TestDelegate(out Action a);

假设我只想调用一个方法,将参数 a 设置为 null
请注意,我知道处理这个问题的更好方法可能是使方法返回 Action 委托,但这只是一个较大项目中的简化部分,该方法已经返回一个值,我还需要处理 out 参数,因此有了这个问题。
我尝试过这样做:
using System;
using System.Text;
using System.Reflection.Emit;

namespace ConsoleApplication8
{
    public class Program
    {
        public delegate void TestDelegate(out Action a);

        static void Main(String[] args)
        {
            var method = new DynamicMethod("TestMethod", typeof(void),
                new Type[] { typeof(Action).MakeByRefType() });
            var il = method.GetILGenerator();

            // a = null;
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Starg, 0);

            // return
            il.Emit(OpCodes.Ret);

            var del = (TestDelegate)method.CreateDelegate(typeof(TestDelegate));
            Action a;
            del(out a);
        }
    }
}

然而,我得到了这个:
VerificationException was unhandled:
Operation could destabilize the runtime.

del(out a);这一行。

请注意,如果我注释掉加载空值并尝试将其存储到参数中的两行代码,则该方法会在没有异常的情况下运行。


编辑: 这是最好的方法吗?

il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldnull);
il.Emit(OpCodes.Stind_Ref);

真的需要创建动态方法吗?为什么不在一个类中实现该方法,可以在运行时进行配置以执行所需操作呢? - Stefan Steinegger
这确实必须是一种动态方法,这是最后一步优化的努力,以使基于反射的巨大调用树执行更快。到目前为止,使用动态方法的开销相对于现有代码似乎要少约85%,而这是将被每秒调用数千次的代码。测量结果显示,现有反射代码中有相当多的CPU被占用。 - Lasse V. Karlsen
1个回答

9

out参数只是一个带有OutAttribute应用于参数的ref参数。

要将值存储到按引用传递的参数中,您需要使用stind操作码,因为参数本身是指向对象实际位置的托管指针。

ldarg.0
ldnull
stind.ref

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接