web-dev-qa-db-fra.com

Différence entre Invoke et DynamicInvoke

Quelle est la différence entre Invoke et DynamicInvoke dans les délégués? S'il vous plaît, donnez-moi un exemple de code qui explique la différence entre ces deux méthodes.

121
testCoder

Lorsque vous avez une instance de délégué, vous pouvez connaître le type exact ou simplement vous assurer qu'il s'agit d'un Delegate. Si vous connaissez le type exact, vous pouvez utiliser Invoke, ce qui est très rapide - tout est déjà pré-validé. Par exemple:

Func<int,int> twice = x => x * 2;
int i = 3;
int j = twice.Invoke(i);
// or just:
int j = twice(i);

Toutefois! Si vous savez simplement que c'est Delegate, il doit résoudre les paramètres, etc. manuellement - cela peut impliquer unboxing, etc. - beaucoup de réflexion est en cours. Par exemple:

Delegate slowTwice = twice; // this is still the same delegate instance
object[] args = { i };
object result = slowTwice.DynamicInvoke(args);

Notez que j'ai écrit la main args longue pour indiquer clairement qu'un object[] est impliqué. Il y a beaucoup de coûts supplémentaires ici:

  • le tableau
  • la validation des arguments passés est un "ajustement" pour le réel MethodInfo
  • unboxing etc si nécessaire
  • invoquer la réflexion
  • alors l'appelant doit faire quelque chose pour traiter la valeur de retour

En gros, évitez DynamicInvoke chaque fois que vous le pouvez. Invoke est toujours préférable, à moins que tout ce que vous avez est un Delegate et un object[].

Pour une comparaison des performances, les éléments suivants en mode publication en dehors du débogueur (un fichier exe de la console) sont imprimés:

Invoke: 19ms
DynamicInvoke: 3813ms

Code:

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);
192
Marc Gravell