Diferencia entre Invoke y DynamicInvoke

¿Cuál es la diferencia entre Invoke y DynamicInvoke en los delegates? Por favor, dame un ejemplo de código que explique la diferencia entre esos dos métodos.

Cuando tiene una instancia de delegado, puede conocer el tipo exacto o simplemente puede saber que es un Delegate . Si conoce el tipo exacto, puede usar Invoke , que es muy rápido : todo está ya validado previamente. Por ejemplo:

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

¡Sin embargo! Si simplemente sabe que es Delegate , tiene que resolver los parámetros, etc. manualmente, esto podría implicar el desempaquetado, etc., se está produciendo una gran cantidad de reflexión. Por ejemplo:

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

Tenga en cuenta que he escrito la args larga args para dejar en claro que un object[] está involucrado. Aquí hay muchos costos adicionales:

  • la matriz
  • validar los argumentos pasados ​​es un “ajuste” para el MethodInfo real
  • desembalaje, etc. según sea necesario
  • invocar a la reflexión
  • entonces la persona que llama necesita hacer algo para procesar el valor de retorno

Básicamente, evita DynamicInvoke cuando puedas. Invoke siempre es preferible, a menos que todo lo que tiene es un Delegate y un object[] .

Para una comparación de rendimiento, se imprime lo siguiente en modo de lanzamiento fuera del depurador (un exe de la consola):

 Invoke: 19ms DynamicInvoke: 3813ms 

Código:

 Func 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);