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 args
mão longa para deixar claro que um object[]
está envolvido. Existem muitos custos extras aqui:
MethodInfo
Basicamente, evite DynamicInvoke
sempre que puder. Invoke
é sempre preferível, a menos que tudo que você tem é um Delegate
e 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?