2009-07-22 16 views
51

¿Cuál es más correcto y por qué?MethodInvoker vs Action para Control.BeginInvoke

Control.BeginInvoke(new Action(DoSomething), null); 

private void DoSomething() 
{ 
    MessageBox.Show("What a great post"); 
} 

o

Control.BeginInvoke((MethodInvoker) delegate { 
    MessageBox.Show("What a great post"); 
}); 

me siento un poco como yo estoy haciendo lo mismo, por lo que cuando es el momento adecuado para usar MethodInvoker vs Action, o incluso escribir una expresión lambda?

EDIT: Yo sé que en realidad no hay mucha diferencia entre escribir una lambda vs Action, pero MethodInvoker parece estar hecho para un propósito específico. ¿Está haciendo algo diferente?

+0

Mira esto, así http://mark-dot-net.blogspot.com.uy/2014/07/six-ways-to-initiate-tasks-on-another.html –

Respuesta

71

Ambos son igualmente correcta, pero la documentación de Control.Invoke establece que:

el delegado puede ser una instancia de manejador de sucesos, en cuyo caso el parámetro remitente contendrá este control, y el parámetro de evento contendrá EventArgs.Empty. El delegado también puede ser ser una instancia de MethodInvoker, o cualquier otro delegado que tome una lista de parámetros vacía. Una llamada a un EventHandler o MethodInvoker delegado será más rápido que una llamada a otro tipo de delegado.

Así que MethodInvoker sería una opción más eficiente.

+0

Gracias Jon, pero ¿qué hace que MethodInvoker sea más eficiente que una llamada a Action sin argumentos? –

+26

Simplemente: parece que comprueba (como casos especiales) para estos dos con una verificación de tipo is/as, y utiliza Invoke, en lugar de DynamicInvoke, que es ** significativamente ** más rápido –

2

Es una cuestión de preferencia en la mayoría de los casos, a menos que tenga la intención de volver a utilizar el método DoSomething(). Además, las funciones anónimas colocarán sus variables de ámbito en el montón, podría hacer que sea una función más costosa.

3

también por MSDN:

MethodInvoker proporciona un delegado simple que se utiliza para invocar un método con una lista de parámetros vacío. Este delegado se puede usar cuando se realizan llamadas al método Invoke de un control, o cuando se necesita un delegado simple pero no se quiere definir uno.

an La acción por otro lado puede tomar hasta 4 parámetros.

Pero no creo que haya ninguna diferencia entre MethodInvoker y Acción, ya que ambos simplemente encapsulan un delegado que no tiene un paremter y devuelve vacío

Si nos fijamos en su las definiciones simplemente verán esto.

public delegate void MethodInvoker(); 
public delegate void Action(); 

btw también podría escribir su segunda línea como.

Control.BeginInvoke(new MethodInvoker(DoSomething), null); 
+0

incluso se puede reescríbalo como: Control.BeginInvoke (nuevo MethodInvoker (DoSomething)); o Control.BeginInvoke (new MethodInvoker ((=) {DoSomething();})); – juFo

4

Acción se define en el sistema, mientras que MethodInvoker se define en System.Windows.Forms - usted puede ser mejor usar la acción, ya que es portable a otros lugares. También encontrarás más lugares que aceptan Acción como parámetro que MethodInvoker.

Sin embargo, la documentación indica que las llamadas a delegados de tipo EventHandler o MethodInvoker en Control.Invoke() serán más rápidas que cualquier otro tipo.

Aparte de los cuales espacio de nombre que se encuentran, no creo que hay una significativa funcional diferencia entre la acción y MethodInvoker - que son esencialmente tanto definen como:

public delegate void NoParamMethod(); 

Dicho sea de paso, tiene acción varias sobrecargas que permiten pasar parámetros, y es genérico para que puedan ser seguros en cuanto a tipo de letra.

+4

Y, a la inversa, Action solo se define en .NET 3.5 ... –

8

Yo prefiero usar lambdas y acciones/funcs:

Control.BeginInvoke(new Action(() => MessageBox.Show("What a great post"))); 
18

Para cada solución abajo I ejecutar un 131072 (128 * 1024) iteraciones (en un hilo separado). El ayudante de interpretación VS2010 dan estos resultados:

  • sólo lectura MethodInvoker: 5.664,53 (+ 0%)
  • Nueva MethodInvoker: 5.828,31 (+ 2,89%)
  • función de conversión en MethodInvoker: 5.857,07 (3,40 %)
  • sólo lectura Acción: 6.467,33 (+ 14,17%)
  • nueva Acción: 6.829,07 (+ 20,56%)

llamada a una nueva Acción en cada iteración

private void SetVisibleByNewAction() 
    { 
     if (InvokeRequired) 
     { 
      Invoke(new Action(SetVisibleByNewAction)); 
     } 
     else 
     { 
      Visible = true; 
     } 
    } 

llamada a una, construir en el constructor, de sólo lectura Acción en cada iteración

// private readonly Action _actionSetVisibleByAction 
    // _actionSetVisibleByAction= SetVisibleByAction; 
    private void SetVisibleByAction() 
    { 
     if (InvokeRequired) 
     { 
      Invoke(_actionSetVisibleByAction); 
     } 
     else 
     { 
      Visible = true; 
     } 
    } 

llamada a una nueva MethodInvoker en cada iteración.

private void SetVisibleByNewMethodInvoker() 
    { 
     if (InvokeRequired) 
     { 
      Invoke(new MethodInvoker(SetVisibleByNewMethodInvoker)); 
     } 
     else 
     { 
      Visible = true; 
     } 
    } 

llamada a una de sólo lectura, la construcción en el constructor, MethodInvoker en cada iteración

// private readonly MethodInvoker _methodInvokerSetVisibleByMethodInvoker 
    // _methodInvokerSetVisibleByMethodInvoker = SetVisibleByMethodInvoker; 
    private void SetVisibleByMethodInvoker() 
    { 
     if (InvokeRequired) 
     { 
      Invoke(_methodInvokerSetVisibleByMethodInvoker); 
     } 
     else 
     { 
      Visible = true; 
     } 
    } 

de llamadas al elenco función en MethodInvoker en cada iteración

private void SetVisibleByDelegate() 
    { 
     if (InvokeRequired) 
     { 
      Invoke((MethodInvoker) SetVisibleByDelegate); 
     } 
     else 
     { 
      Visible = true; 
     } 
    } 

Ejemplo de llamada para la solución "Nueva acción":

private void ButtonNewActionOnClick(object sender, EventArgs e) 
    { 
     new Thread(TestNewAction).Start(); 
    } 

    private void TestNewAction() 
    { 
     var watch = Stopwatch.StartNew(); 
     for (var i = 0; i < COUNT; i++) 
     { 
      SetVisibleByNewAction(); 
     } 
     watch.Stop(); 
     Append("New Action: " + watch.ElapsedMilliseconds + "ms"); 
    } 
0

No olvide verificar de alguna manera si el control está disponible en este momento, para evitar errores al cerrar el formulario.

if(control.IsHandleCreated) 
control.BeginInvoke((MethodInvoker)(() => control.Text="check123")); 
Cuestiones relacionadas