调用与动态调用的区别

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

54213 次浏览

当您有一个委托实例时,您可能知道确切的类型,或者您可能只知道它是一个 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的“适合”
  • 必要时拆箱等
  • 反射-调用
  • 然后调用者需要做一些事情来处理返回值

基本上,尽可能避免 DynamicInvoke。除非你只有 Delegateobject[],否则 Invoke总是更好。

为了进行性能比较,将输出以下调试器(控制台 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);