一尘不染

调用和DynamicInvoke之间的区别

c#

委托中的Invoke和DynamicInvoke有什么区别?请给我一些代码示例,说明这两种方法之间的区别。


阅读 360

收藏
2020-05-19

共1个答案

一尘不染

当您有一个委托实例时,您可能知道确切的类型,或者可能只是知道它是一个Delegate。如果您知道确切的类型,则可以使用Invoke,它
非常快 -一切都已预先验证。例如:

Func<int,int> twice = x => x * 2;
int i = 3;
int j = twice.Invoke(i);
// or just:
int j = twice(i);

然而!如果您只是知道它是Delegate,它必须手动解析参数等-这可能涉及拆箱等-正在进行很多反射。例如:

Delegate slowTwice = twice; // this is still the same delegate instance
object[] args = { i };
object result = slowTwice.DynamicInvoke(args);

请注意,我已经写了args很长的篇幅以明确指出object[]涉及到了。这里有很多额外费用:

  • 数组
  • 验证传递的参数是否适合实际 MethodInfo
  • 拆箱等必要
  • 反射调用
  • 那么调用者需要做一些事情来处理返回值

基本上,尽可能避免DynamicInvokeInvoke总是可取的,除非您所拥有的都是a Delegate和an object[]

为了进行性能比较,在调试器(控制台exe)之外的释放模式下打印以下内容:

Invoke: 19ms
DynamicInvoke: 3813ms

码:

Func<int,int> twice = x => x * 2;
const int LOOP = 5000000; // 5M
var watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
    twice.Invoke(3);
}
watch.Stop();
Console.WriteLine("Invoke: {0}ms", watch.ElapsedMilliseconds);
watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
    twice.DynamicInvoke(3);
}
watch.Stop();
Console.WriteLine("DynamicInvoke: {0}ms", watch.ElapsedMilliseconds);
2020-05-19