Respostas:
Quando você tem uma instância delegada, pode saber o tipo exato ou apenas saber que é a Delegate. Se você souber o tipo exato, poderá usar Invoke, o que é muito rápido - tudo já está pré-validado. Por exemplo:
Func<int,int> twice = x => x * 2;
int i = 3;
int j = twice.Invoke(i);
// or just:
int j = twice(i);
Contudo! Se você apenas sabe que é Delegate, ele tem que resolver os parâmetros, etc. manualmente - isso pode envolver descompactação, etc. - muita reflexão está acontecendo. Por exemplo:
Delegate slowTwice = twice; // this is still the same delegate instance
object[] args = { i };
object result = slowTwice.DynamicInvoke(args);
Observe que escrevi a argsmão longa para deixar claro que um object[]está envolvido. Existem muitos custos extras aqui:
MethodInfoBasicamente, evite DynamicInvokesempre que puder. Invokeé sempre preferível, a menos que tudo que você tem é um Delegatee um object[].
Para uma comparação de desempenho, é impresso o seguinte no modo de liberação fora do depurador (um exe do console):
Invoke: 19ms
DynamicInvoke: 3813ms
Código:
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);
Invoke: 0,0478ms, DynamicInvoke: 0,053ms. Por que você os está comparando mais de uma ligação? E por que o primeiro demora mais que a segunda chamada de função?