为什么 `dynamicMethod.CreateDelegate(typeof(Action)).Method.Invoke(null,new object[0]);` 抛出异常?

Why does `dynamicMethod.CreateDelegate(typeof(Action)).Method.Invoke(null,new object[0]);` throw an Exception?

这似乎可行,提供了一种(奇怪的)方式来调用 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 must be a runtime MethodInfo object.

问题:为什么上面的代码片段会抛出一个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 must be a runtime MethodInfo object.

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

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