2012-10-12 54 views

回答

160

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

基本上,在y时应避免DynamicInvoke你可以。 Invoke总是更可取,除非您拥有的是Delegateobject[]

对于性能比较,在释放模式调试器的外部设置(控制台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); 
+3

这是否意味着在使用的DynamicInvoke的情况下,编译器生成更多的IL代码来处理委托调用? – testCoder

+1

@testCoder不,它会使用反射 –

+2

谢谢,非常全面的解释。 – testCoder