it-swarm.com.de

MethodInvoker vs Aktion für Control.BeginInvoke

Welcher ist richtiger und warum?

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

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

oder

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

Ich habe das Gefühl, dass ich dasselbe mache, wann ist es also an der Zeit, MethodInvoker vs. Action zu verwenden oder sogar einen Lambda-Ausdruck zu schreiben?

EDIT: Ich weiß, dass es keinen großen Unterschied zwischen dem Schreiben eines Lambda vs. Action gibt, aber MethodInvoker scheint für einen bestimmten Zweck gemacht zu sein. Macht es etwas anderes?

55
Mike_G

Beide sind gleichermaßen korrekt, aber die Dokumentation für Control.Invoke besagt Folgendes:

Der Delegat kann eine Instanz von .__ sein. EventHandler, in diesem Fall der Absender Der Parameter enthält dieses Steuerelement und der Ereignisparameter enthält EventArgs.Empty. Der Delegierte kann auch eine Instanz von MethodInvoker oder .__ sein. jeder andere Delegat, der ungültig ist Parameterliste. Ein Anruf an eine EventHandler- oder MethodInvoker-Delegat ist schneller als ein Anruf an eine andere Art des Delegierten.

MethodInvoker wäre also eine effizientere Wahl.

74
Jon Skeet

Für jede Lösung unten führe ich eine 131072 (128 * 1024) Iteration (in einem separaten Thread) aus .. Der VS2010-Leistungsassistent gibt diese Ergebnisse aus:

  • schreibgeschütztes MethodInvoker: 5664.53 (+ 0%)
  • Neue MethodInvoker: 5828.31 (+ 2.89%)
  • funktion umgewandelt in MethodInvoker: 5857.07 (+ 3.40%)
  • nur-Lese-Aktion: 6467.33 (+ 14,17%)
  • Neue Aktion: 6829,07 (+ 20,56%)

Bei jeder Iteration eine neue Action aufrufen

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

Rufen Sie bei jeder Iteration einen schreibgeschützten Build-Konstruktor Action auf

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

Rufen Sie bei jeder Iteration einen neuen MethodInvoker auf.

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

Rufen Sie bei jeder Iteration einen schreibgeschützten Build-Konstruktor MethodInvoker auf

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

Ruft bei jeder Iteration die in MethodInvoker umgesetzte Funktion auf

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

Aufrufbeispiel für die Lösung "Neue Aktion":

    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

Ich bevorzuge Lambdas und Actions/Funcs:

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

Action ist in System definiert, während MethodInvoker in System.Windows.Forms definiert ist. Action ist möglicherweise besser für Sie geeignet, da es auf andere Orte übertragbar ist. Sie finden auch mehr Stellen, die Action als Parameter akzeptieren als MethodInvoker.

In der Dokumentation wird jedoch angegeben, dass Aufrufe von Delegaten des Typs EventHandler oder MethodInvoker in Control.Invoke () schneller sind als alle anderen Typen.

Abgesehen davon, in welchem ​​Namensraum sie sich befinden, glaube ich nicht, dass es einen bedeutungsvollen funktionalen Unterschied zwischen Action und MethodInvoker gibt - sie sind im Wesentlichen beide definiert als:

public delegate void NoParamMethod();

Daneben gibt es in Action mehrere Überladungen, mit denen Parameter übergeben werden können - und sie sind generisch, damit sie typsicher sind.

4
LBushkin

Auch per MSDN:

MethodInvoker stellt einen einfachen Delegaten bereit, mit dem eine Methode mit einer ungültigen Parameterliste aufgerufen wird. Dieser Delegat kann verwendet werden, wenn die Invoke-Methode eines Steuerelements aufgerufen wird oder wenn Sie einen einfachen Delegat benötigen, das Sie jedoch nicht selbst definieren möchten. 

eine Action dagegen kann bis zu 4 Parameter annehmen.

Aber ich glaube nicht, dass es einen Unterschied zwischen MethodInvoker und Action gibt, da beide einfach einen Delegaten kapseln, der keinen Parent-Platz benötigt und void zurückgibt.

Wenn Sie ihre Definitionen betrachten, sehen Sie dies einfach.

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

Übrigens könnte man auch als zweite Zeile schreiben.

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

In den meisten Fällen ist dies eine Frage der Präferenz, es sei denn, Sie beabsichtigen, die DoSomething () - Methode erneut zu verwenden. Auch die anonymen Funktionen platzieren Ihre Bereichsvariablen auf dem Heap und machen sie möglicherweise teurer.

2

Vergessen Sie nicht, irgendwie zu prüfen, ob die Steuerung momentan verfügbar ist, um Fehler beim Schließen des Formulars zu vermeiden.

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