这似乎可行,它提供了一种(奇怪的)方式来调用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
之间的区别是什么。
答案 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