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

时间:2018-09-21 01:55:23

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

这似乎可行,它提供了一种(奇怪的)方式来调用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对象。

问题:为什么上面的代码片段会抛出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是“ MethodInfo ”,但它不是“ 运行时MethodInfo ”。不过,我不太确定运行时MethodInfo和非运行时MethodInfo之间的区别是什么。

1 个答案:

答案 0 :(得分: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