【问题标题】:C# Reflection Emit Call with parameter带参数的 C# 反射发射调用
【发布时间】:2020-05-17 20:35:34
【问题描述】:

我想使用reflection.emit API 调用带有参数的函数。以下是我目前所拥有的。但是当我运行它时,它会抛出以下异常:System.InvalidProgramException : Common Language Runtime detected an invalid program。所以我的问题是我在下面的代码 sn-p 中有什么问题?有人可以帮帮我吗?

public class Test
{

    public void test()
    {
        Func<int, long> realSquareFunc = (val) => val * val;
        Type[] methodArgs = { typeof(int) };

        DynamicMethod squareIt = new DynamicMethod(
            "SquareIt",
            typeof(long),
            methodArgs,
            typeof(Test).Module)
        ;

        ILGenerator il = squareIt.GetILGenerator();
        il.Emit(OpCodes.Ldarg_0); // Save parameter on stack
        il.Emit(OpCodes.Call, realSquareFunc.Method); // Call function with input as parameter
        il.Emit(OpCodes.Ret); // Return value from function call before

        var myMethod = (Func<int, long>)squareIt.CreateDelegate(realSquareFunc.GetType());
        var result = myMethod.Invoke(4); // Should be 16 (4*4)
    }

}

【问题讨论】:

    标签: c# reflection func reflection.emit dynamicmethod


    【解决方案1】:

    如果调用的方法是静态方法,您的代码将按原样运行:

    public static long RealSquare(int val) => val * val;
    
    public void test()
    {
        Func<int, long> realSquareFunc = RealSquare;
        // ...
    

    但是,realSquareFunc = (val) =&gt; val * val lambda 实际上被编译为隐藏类的实例方法。要调用实例方法,必须先将实例压入堆栈,在方法参数之前。实例方法调用通常也使用Callvirt 操作码(不管它们是否是虚拟的,因为此操作码会进行空引用检查):

    public class Test
    {
        public long RealSquare(int val) => val * val;
    
        public void test()
        {
            Func<int, long> realSquareFunc = RealSquare;
            // pass the instance we want to call the method on in as well
            Type[] methodArgs = { typeof(Test), typeof(int) };
    
            DynamicMethod squareIt = new DynamicMethod(
                "SquareIt",
                typeof(long),
                methodArgs,
                typeof(Test).Module)
            ;
    
            ILGenerator il = squareIt.GetILGenerator();
            il.Emit(OpCodes.Ldarg_0); // Push the target instance onto stack      
            il.Emit(OpCodes.Ldarg_1); // Save parameter on stack
            il.Emit(OpCodes.Callvirt, realSquareFunc.Method); // Call function with input as parameter
            il.Emit(OpCodes.Ret); // Return value from function call before
    
            var myMethod = (Func<Test, int, long>)squareIt.CreateDelegate(typeof(Func<Test, int, long>));
            var result = myMethod.Invoke(this, 4); // Should be 16 (4*4)
        }  
    }
    

    由于涉及到编译器生成的类,直接调用 lambda 的目标方法更加复杂,但如果您想调用委托,它的工作原理一般如下:

    public class Test
    {        
        public void test()
        {
            Func<int, long> realSquareFunc = (val) => val * val;
            // pass the delegate we want to call into the method
            Type[] methodArgs = { realSquareFunc.GetType(), typeof(int) };
    
            DynamicMethod squareIt = new DynamicMethod(
                "SquareIt",
                typeof(long),
                methodArgs,
                typeof(Test).Module)
            ;
    
            ILGenerator il = squareIt.GetILGenerator();
            il.Emit(OpCodes.Ldarg_0); // Push the delegate onto stack        
            il.Emit(OpCodes.Ldarg_1); // Save parameter on stack
            il.Emit(OpCodes.Callvirt, realSquareFunc.GetType().GetMethod("Invoke")); // Invoke delegate
            il.Emit(OpCodes.Ret); // Return value from function call before
    
            var myMethod = (Func<Func<int, long>, int, long>)squareIt
                .CreateDelegate(typeof(Func<Func<int, long>, int, long>));
            var result = myMethod.Invoke(realSquareFunc, 4); // Should be 16 (4*4)
        }  
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-19
      • 2015-09-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多