【问题标题】:Why does `dynamicMethod.CreateDelegate(typeof(Action)).Method.Invoke(null,new object[0]);` throw an Exception?为什么`dynamicMethod.CreateDelegate(typeof(Action)).Method.Invoke(null,new object[0]);`会抛出异常?
【发布时间】:2018-09-21 01:55:22
【问题描述】:

这似乎有效,提供了一种(奇怪的)调用Action的方式:

Action action = () => { };
action.Method.Invoke(action.Target, new object[0]);

这似乎有效,提供了一种(有用的)方法来创建Action:

var action = dynamicMethod.CreateDelegate(typeof(Action)) as Action;
action();

但是,这会引发 Exception:

var action = dynamicMethod.CreateDelegate(typeof(Action)) as Action;
action.Method.Invoke(action.Target, new object[0]);  // Throws exception

MethodInfo 必须是运行时 MethodInfo 对象。

问题:为什么上面的代码sn-p会抛出Exception?


工作代码示例

var dynamicMethod = new System.Reflection.Emit.DynamicMethod(
            ""
        ,   typeof(void)
        ,   new Type[0]
    );

var ilGenerator = dynamicMethod.GetILGenerator();
ilGenerator.Emit(System.Reflection.Emit.OpCodes.Ret);
var action = dynamicMethod.CreateDelegate(typeof(Action)) as Action;

try
{
    action.Method.Invoke(action.Target, new object[0]);
}
catch (Exception exception)
{
    System.Console.WriteLine(exception);
}

这会导致Console 写入:

Exception thrown: 'System.ArgumentException' in mscorlib.dll
System.ArgumentException: MethodInfo must be a runtime MethodInfo object.
Parameter name: this
  at System.Reflection.Emit.DynamicMethod.RTDynamicMethod.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
  at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
  [...]

想法

我在调用 action.Method.Invoke() 时尝试了很多变体,但调用参数的各种变体似乎都不会改变异常消息,

MethodInfo 必须是运行时 MethodInfo 对象。

我猜action.Method 不是“runtime MethodInfo”,尽管它是“MethodInfo”。不过,我不太确定运行时-MethodInfo 和非运行时-MethodInfo 之间的区别可能是什么。

【问题讨论】:

  • 你不需要创建一个类型并从中获取方法信息吗?喜欢here?
  • @John 我还没有测试过,但这可能有用吗?我的意思是,这是我有解决方法的情况之一,所以我真的不需要解决方案,而是想弄清楚为什么这种特殊方法会意外失败。

标签: c# delegates invoke system.reflection reflection.emit


【解决方案1】:

MethodInfo 是一种抽象类型,有多种实现方式。

其中一个是内部类型System.Reflection.RuntimeMethodInfo。当您反映现有运行时类型的方法时,您会得到以下结果:

Console.WriteLine(typeof(object).GetMethod("ToString").GetType().FullName); // System.Reflection.RuntimeMethodInfo

另一方面,DynamicMethod.CreateDelegate 使用MethodInfo 的另一种实现:

Console.WriteLine(action.Method.GetType().FullName); // System.Reflection.Emit.DynamicMethod+RTDynamicMethod

而且它似乎不支持MethodInfo.Invoke 的调用。

但是如果你因为某种原因不能使用你创建的委托的Invoke方法(例如因为你不知道确切的委托类型),你仍然可以使用Delegate.DynamicInvoke方法(但是,动态调用委托的速度几乎与反射 API 一样慢):

Delegate del = action; // let's assume you don't know the delegate type
del.DynamicInvoke(); // slow as hell but works without throwing an exception

【讨论】:

    猜你喜欢
    • 2014-12-12
    • 2023-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-25
    • 1970-01-01
    • 2022-01-15
    相关资源
    最近更新 更多