web-dev-qa-db-fra.com

MethodInvoker vs Action pour Control.BeginInvoke

Lequel est le plus correct et pourquoi?

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

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

ou

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

J'ai le sentiment que je fais la même chose, alors quel est le bon moment pour utiliser MethodInvoker contre Action, ou même pour écrire une expression lambda?

EDIT: Je sais qu'il n'y a pas vraiment de différence entre écrire un lambda et Action, mais MethodInvoker semble avoir été créé dans un but précis. Fait-il quelque chose de différent?

55
Mike_G

Les deux sont également corrects, mais la documentation de Control.Invoke indique que:

Le délégué peut être une instance de EventHandler, auquel cas l'expéditeur paramètre contiendra ce contrôle, et le paramètre event contiendra EventArgs.Empty. Le délégué peut également être une instance de MethodInvoker, ou tout autre délégué qui prend un vide liste de paramètres. Un appel à un Délégué EventHandler ou MethodInvoker sera plus rapide qu'un appel à un autre type de délégué.

Donc MethodInvoker serait un choix plus efficace.

74
Jon Skeet

Pour chaque solution ci-dessous, j'exécute une série de 131072 (128 * 1024) itérations (dans un thread séparé) .

  • en lecture seule MethodInvoker: 5664.53 (+ 0%)
  • Nouveau MethodInvoker: 5828.31 (+ 2.89%)
  • fonction exprimée dans MethodInvoker: 5857.07 (+ 3.40%)
  • action en lecture seule: 6467.33 (+ 14.17%)
  • Nouvelle action: 6829.07 (+ 20,56%)

Appel à un nouveau Action à chaque itération

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

Appel à un constructeur en lecture seule, intégré, Action à chaque itération

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

Appelez un nouveau MethodInvoker à chaque itération.

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

Appel à un constructeur en lecture seule, construit, MethodInvoker à chaque itération

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

Appel de la fonction convertie dans MethodInvoker à chaque itération

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

Exemple d'appel pour la solution "Nouvelle action":

    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");
    }
25
Orace

Je préfère utiliser lambdas et Actions/Funcs:

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

Action est défini dans System, tandis que MethodInvoker est défini dans System.Windows.Forms. Il est peut-être préférable d’utiliser Action, car il est portable vers d’autres emplacements. Vous trouverez également plus d'endroits qui acceptent Action en tant que paramètre que MethodInvoker.

Toutefois, la documentation indique que les appels aux délégués de type EventHandler ou MethodInvoker dans Control.Invoke () seront plus rapides que tout autre type.

Hormis le nom de la cible où ils se trouvent, je ne crois pas qu'il y ait une différence significative fonctionnelle entre Action et MethodInvoker. Ils sont essentiellement définis comme suit:

public delegate void NoParamMethod();

En passant, Action comporte plusieurs surcharges qui permettent de passer des paramètres - et il est générique afin de pouvoir protéger les types.

4
LBushkin

Aussi par MSDN:

MethodInvoker fournit un simple délégué utilisé pour invoquer une méthode avec une liste de paramètres void. Ce délégué peut être utilisé lors d'appels à la méthode Invoke d'un contrôle ou lorsque vous avez besoin d'un simple délégué mais que vous ne souhaitez pas en définir vous-même. 

par contre, une Action peut prendre jusqu'à 4 paramètres.

Mais je ne pense pas qu'il y ait de différence entre MethodInvoker et Action, car ils encapsulent tous les deux un délégué qui ne prend pas de paragraphe et renvoie void

Si vous regardez leurs définitions, vous verrez simplement ceci.

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

en outre, vous pouvez également écrire votre deuxième ligne sous la forme.

Control.BeginInvoke(new MethodInvoker(DoSomething), null);
3
Stan R.

C'est une question de préférence dans la plupart des cas, sauf si vous avez l'intention de réutiliser la méthode DoSomething (). De plus, les fonctions anonymes placeront vos variables étendues sur le tas, ce qui pourrait en faire une fonction plus coûteuse.

2
Yuriy Faktorovich

N'oubliez pas de vérifier si le contrôle est disponible pour le moment, pour éviter les erreurs lors de la fermeture du formulaire.

if(control.IsHandleCreated)
control.BeginInvoke((MethodInvoker)(() => control.Text="check123"));
0
Tomek