为什么 `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
这似乎可行,提供了一种(奇怪的)方式来调用 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