MethodInvoker vs d'Action pour le Contrôle.BeginInvoke

Qu'est-ce qui 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 un peu l'impression de faire la même chose, alors quand est le bon moment pour utiliser MethodInvoker vs Action , ou même écrire une expression lambda?

EDIT: je sais qu'il n'y a pas vraiment beaucoup de différence entre l'écriture d'un lambda vs Action , mais MethodInvoker semble être fait pour un but précis. Être il en train de faire quelque chose de différent?

53
demandé sur Otiel 2009-07-22 23:47:11

7 réponses

les deux sont également corrects, mais la documentation pour Control.Invoke stipule que:

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

donc MethodInvoker serait un choix plus efficace.

72
répondu Jon Skeet 2009-07-22 19:55:14

pour chaque solution ci-dessous, je lance une itération de 131072 (128*1024) (dans un thread séparé). L'assistant de performance VS2010 donne ce résultat:

  • lecture seule MethodInvoker: 5664.53 (+0%)
  • New MethodInvoker: 5828.31 (+2,89%)
  • fonction moulée en MethodInvoker: 5857.07 (+3.40%)
  • action en lecture seule: 6467.33 (+14.17%)
  • Nouvelle Action: 6829.07 (+20.56%)

appel à une nouvelle Action à chaque itération

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

Appel pour une lecture seule, de construire dans le constructeur, Action à chaque itération

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

appel à un nouveau MethodInvoker à chaque itération.

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

appel à une lecture seule, construire dans le constructeur, MethodInvoker à chaque itération

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

appel à la fonction moulée dans MethodInvoker à chaque itération

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

exemple d'appel à 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");
    }
22
répondu Orace 2014-09-17 09:44:13

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

Control.BeginInvoke(new Action(() => MessageBox.Show("What a great post")));
9
répondu Will 2009-07-22 19:56:54

Action est définie dans le système, tandis que MethodInvoker est défini dans le système.Windows.Formulaires - vous pouvez être mieux en utilisant L'Action, car il est portable à d'autres endroits. Vous trouverez aussi plus d'endroits qui acceptent L'Action comme paramètre que MethodInvoker.

cependant, la documentation indique que les appels aux délégués de type EventHandler ou MethodInvoker en contrôle.Invoke () sera plus rapide que n'importe quel autre type.

mis à part lequel namepsace qu'ils sont, je ne crois pas qu'il existe un véritable fonctionnelle la différence entre l'Action et la MethodInvoker - ils sont essentiellement de deux définie comme:

public delegate void NoParamMethod();

comme un côté, Action a plusieurs surcharges qui permettent aux paramètres d'être passés - et il est générique afin qu'ils puissent être typesafe.

4
répondu LBushkin 2009-07-22 19:54:10

également par MSDN:

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

un Action sur l'autre main peut prendre jusqu'à 4 paramètres.

mais je ne pense pas qu'il y ait n'importe quelle différence entre MethodInvoker et Action car ils tous les deux simplement encapsuler un délégué qui ne prend pas un paremter et retourne nul

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

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

btw, vous pouvez également écrire votre deuxième ligne.

Control.BeginInvoke(new MethodInvoker(DoSomething), null);
3
répondu Stan R. 2009-07-22 20:01:10

c'est une question de préférence dans la plupart des cas, à moins que vous n'ayez l'intention de réutiliser la méthode DoSomething (). Aussi les fonctions anonymes placeront vos variables scoped sur le tas, pourrait en faire une fonction plus chère.

2
répondu Yuriy Faktorovich 2009-07-22 19:51:14

n'oubliez pas de vérifier d'une manière ou d'une autre si le contrôle est disponible en ce moment, pour éviter des erreurs à la fermeture de la forme.

if(control.IsHandleCreated)
control.BeginInvoke((MethodInvoker)(() => control.Text="check123"));
0
répondu Tomek 2017-12-20 11:55:55