2012-10-12 34 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