【问题标题】:DynamicMethod call terminated due to a StackOverFlowExceptionDynamicMethod 调用因 StackOverFlowException 而终止
【发布时间】:2018-09-06 23:45:16
【问题描述】:

我有这个类(简化示例)

public class Foo
{
    public object Bar(Type type)
    {
        return new object();
    }
}

我想在Bar的实例上调用Bar方法使用DynamicMethod,如下所示:

MethodInfo methodInfo = typeof(Foo).GetMethod(nameof(Foo.Bar), new[] { typeof(Type) });
DynamicMethod method = new DynamicMethod("Dynamic Bar", 
                                         typeof(object), 
                                         new []{ typeof(Type) }, 
                                         typeof(Foo).Module);

ILGenerator ilGenerator = method.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.EmitCall(OpCodes.Call, method, null); // I feel like this is wrong...
ilGenerator.Emit(OpCodes.Ret);

Func<Type, object> func = (Func<Type, object>) method.CreateDelegate(typeof(Func<Type, object>));

// Attempt to call the function:
func(typeof(Foo));

但是,它并没有按预期工作,而是中止

进程因 StackOverFlowException 而终止。


谁能告诉我我做错了什么?是不是参数不匹配? 如何在Bar 的特定实例上调用Func?

【问题讨论】:

    标签: c# dynamicmethod ilgenerator


    【解决方案1】:
    ilGenerator.EmitCall(OpCodes.Call, method, null); // I feel like this is wrong...
    

    你目前正在写作 method;您可能打算在这里致电methodInfo。请注意,这需要static 方法才能使用Call - 如果它是实例方法,您可能应该使用CallVirt。由于您没有传入Foo 的实例,因此尚不清楚目标实例将来自何处;您需要将 两个 值加载到堆栈中以调用实例方法 Foo.Bar(Type type) - 而您目前只加载一个。

    显示Delegate.CreateDelegate的用法:

    var methodInfo = typeof(Foo).GetMethod(nameof(Foo.Bar), new[] { typeof(Type) });
    var foo = new Foo();
    
    // if Foo is known ahead of time:
    var f1 = (Func<Type, object>)Delegate.CreateDelegate(
        typeof(Func<Type, object>), foo, methodInfo);
    
    // if Foo is only known per-call:
    var f2 = (Func<Foo, Type, object>)Delegate.CreateDelegate(
        typeof(Func<Foo, Type, object>), null, methodInfo);
    
    Console.WriteLine(f1(typeof(string)));
    
    Console.WriteLine(f2(foo, typeof(string)));
    

    【讨论】:

    • @ThomasFlinkow 与 DynamicMethod 相比?我认为(基于十多年的 IL-emit 工作)您可能不会通过使用 ILGenerator/MethodBuilder.CreateDelegate 而不是 Delegate.CreateDelegate 来提高性能。这些方法中的任何一种都非常有效只要您正确缓存生成的实例。
    • @ThomasFlinkow 还看到我关于需要 Foo 实例的更新
    • @ThomasFlinkow 不,Delegate.CreateDelegate 与MethodInfo.Invoke非常不同,Delegate.CreateDelegate快得多,只要因为你存储了委托,而不是每次调用都创建它。
    • @ThomasFlinkow 好吧,Foo 实例来自哪里?您不能将其“存储”在 DynamicMethod 上 - 无处可存储。三个选项:您创建一个Func&lt;Foo, Type, object&gt; 代替(并使用arg0/arg1),或者您创建一个带有字段的TypeBuilder,以及分配该字段的构造函数,并使用ldarg0, ldfld_s {fld}, ldarg1;或第三个选项:Delegate.CreateDelegate 已经采用目标实例
    • @ThomasFlinkow 为这两种情况添加了Delegate.CreateDelegate 的完整示例(Foo 提前知道,而Foo 每次调用都知道)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-04
    • 1970-01-01
    • 2020-11-02
    • 1970-01-01
    • 2014-11-18
    • 1970-01-01
    相关资源
    最近更新 更多