web-dev-qa-db-ja.com

MethodInvokerとControl.BeginInvokeのアクション

どちらがより正確で、なぜですか?

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

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

または

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

私は同じことをしているように感じるので、いつ_MethodInvoker vs Actionを使用するか、ラムダ式を書くのが適切なときですか?

編集:ラムダの書き込みとActionの作成との間に実際には大きな違いはないことを知っていますが、MethodInvokerは特定の目的のために作成されたようです。何か違うことをしていますか?

56
Mike_G

どちらも同様に正しいですが、 Control.Invoke の状態:

デリゲートはEventHandlerのインスタンスにすることができます。その場合、senderパラメーターにはこのコントロールが含まれ、eventパラメーターにはEventArgs.Emptyが含まれます。デリゲートは、MethodInvokerのインスタンス、またはvoidパラメーターリストを受け取る他のデリゲートにすることもできます。 EventHandlerまたはMethodInvokerデリゲートの呼び出しは、別の種類のデリゲートの呼び出しよりも高速です。

したがって、MethodInvokerがより効率的な選択になります。

76
Jon Skeet

以下の各ソリューションに対して、131072(128 * 1024)の反復を(1つの分離されたスレッドで)実行します。 VS2010パフォーマンスアシスタントの結果は次のとおりです。

  • 読み取り専用のMethodInvoker:5664.53(+ 0%)
  • 新しいMethodInvoker:5828.31(+ 2.89%)
  • methodInvokerでの関数キャスト:5857.07(+ 3.40%)
  • 読み取り専用アクション:6467.33(+ 14.17%)
  • 新しいアクション:6829.07(+ 20.56%)

繰り返しごとに新しいActionを呼び出す

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

読み取り専用の呼び出し、コンストラクターでビルド、各反復でAction

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

各反復で新しいMethodInvokerを呼び出します。

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

読み取り専用の呼び出し、コンストラクターでビルド、MethodInvoker各反復で

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

各反復でMethodInvokerでキャストされた関数の呼び出し

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

「新しいアクション」ソリューションの呼び出しの例:

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

私はラムダとアクション/機能の使用を好みます:

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

ActionはSystemで定義されますが、MethodInvokerはSystem.Windows.Formsで定義されます-他の場所に移植できるので、Actionを使用した方が良いかもしれません。また、Actionをパラメーターとして受け入れる場所は、MethodInvokerよりも多くあります。

ただし、ドキュメントには、Control.Invoke()のEventHandler型またはMethodInvoker型のデリゲートの呼び出しが他のどの型よりも高速になることが示されています。

それらがどのネームスペースにあるかは別として、意味のあるfunctional ActionとMethodInvokerの違いがあるとは思わない-基本的に両方とも次のように定義される:

public delegate void NoParamMethod();

余談ですが、Actionにはパラメーターを渡すことができるいくつかのオーバーロードがあります。これはジェネリックであるため、タイプセーフになります。

5
LBushkin

また、MSDNごと:

MethodInvokerは、voidパラメータリストを使用してメソッドを呼び出すために使用される単純なデリゲートを提供します。このデリゲートは、コントロールのInvokeメソッドを呼び出す場合、または単純なデリゲートが必要であるが、自分で定義したくない場合に使用できます。

一方、Actionは、最大4つのパラメーターを取ることができます。

しかし、MethodInvokerActionに違いはないと思いますどちらも単純に、パレムターを使用せずにvoidを返すデリゲートをカプセル化するため

それらの定義を見ると、これが表示されます。

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

ところで、2行目を次のように書くこともできます。

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

DoSomething()メソッドを再利用する場合を除き、ほとんどの場合、これは好みの問題です。また、匿名関数はスコープ変数をヒープに配置するため、より高価な関数になる可能性があります。

2

フォームを閉じる際のエラーを回避するために、現時点でコントロールが利用可能かどうかを何らかの形で確認することを忘れないでください。

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