【问题标题】:C# - Reflection.Emit : Return result of called methodC# - Reflection.Emit : 返回被调用方法的结果
【发布时间】:2020-05-26 21:43:00
【问题描述】:

在 DynamicMethod 中,我尝试调用一个希望对象数组返回给定数组长度的方法。目前,我应该从 DynamicMethod 调用的方法如下所示:

public static int Test(Object[] args)
{
    Console.WriteLine(args.Length);
    return args.Length;
}

DynamicMethod的创建过程如下:

(Object数组的创建采用以下SO answer

public static DynamicMethod GetDM()
{ 
    var returnType = typeof(int);
    var paramTypes = new Type[]{typeof(string), typeof(bool)};

    var method = new DynamicMethod(
        "",
        returnType,
        paramTypes,
        false
    );
    var il = method.GetILGenerator();

    // Save parameters in an object array
    il.Emit(OpCodes.Ldc_I4_S, paramTypes.Length);
    il.Emit(OpCodes.Newarr, typeof(Object));
    il.Emit(OpCodes.Dup);

    for (int i = 0; i < paramTypes.Length; i++)
    {
        Type type = paramTypes[i];

        il.Emit(OpCodes.Ldc_I4, i);
        il.Emit(OpCodes.Ldarg, i);
        if (type.IsValueType) { il.Emit(OpCodes.Box, type); }
        il.Emit(OpCodes.Stelem_Ref);
        il.Emit(OpCodes.Dup);
    }

    // Call method and get the length of the array
    // How do I return the result of the called method?
    var callMethod = typeof(Program).GetMethod("Test", (BindingFlags)(-1));
    il.Emit(OpCodes.Call, callMethod);

    il.Emit(OpCodes.Ret);

    return method;
}

我通过以下方法检查功能:

public static void Main(string[] args)
{
    var method = GetDM();
    var result = method.Invoke(null, new Object[]{"Test 1234", true});
    Console.WriteLine(result); // Should be 2
}

当我运行 main 方法时,我得到了System.Reflection.TargetInvocationException。有人可以帮助我如何返回被调用方法返回的值吗?这是 dotnetfiddle 的 link,可以查看我的问题。

【问题讨论】:

  • 你看到你有一个内部异常吗? JIT 编译器遇到无效的 IL 代码或内部限制。
  • @Michael 我是这个领域的新手。但是我发现我需要弹出对象数组,我的方法调用的结果可以放在评估堆栈的顶部。

标签: c# reflection reflection.emit dynamicmethod


【解决方案1】:

for 循环之后,您在堆栈上有两次构造的对象数组(因为Dup 调用)。 Call 只使用这些数组引用中的一个,因此在方法结束时,堆栈上将有一个额外的数组引用。

要纠正这个问题,删除第一个 Dup 并将第二个移到循环体的头部:

public static DynamicMethod GetDM() {  
    var returnType = typeof(int);
    var paramTypes = new Type[]{typeof(string), typeof(bool)};

    var method = new DynamicMethod(
        "",
        returnType,
        paramTypes,
        false
    );
    var il = method.GetILGenerator();

    // Save parameters in an object array
    il.Emit(OpCodes.Ldc_I4_S, paramTypes.Length);
    il.Emit(OpCodes.Newarr, typeof(Object));

    for (int i = 0; i < paramTypes.Length; i++)
    {
        Type type = paramTypes[i];

        il.Emit(OpCodes.Dup);
        il.Emit(OpCodes.Ldc_I4, i);
        il.Emit(OpCodes.Ldarg, i);
        if (type.IsValueType) { il.Emit(OpCodes.Box, type); }
        il.Emit(OpCodes.Stelem_Ref);
    }

    // Call method and get the length of the array
    // How do I return the result of the called method?
    var callMethod = typeof(Program).GetMethod("Test", (BindingFlags)(-1));
    il.Emit(OpCodes.Call, callMethod);

    il.Emit(OpCodes.Ret);

    return method;
}

【讨论】:

    猜你喜欢
    • 2016-03-23
    • 2015-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-28
    • 1970-01-01
    • 1970-01-01
    • 2019-01-20
    相关资源
    最近更新 更多