Invoke呼び出しの匿名メソッド


131

Control.Invoke内でデリゲートを匿名で呼び出す構文に少し問題があります。

私たちは多くの異なるアプローチを試みましたが、どれも役に立ちませんでした。

例えば:

myControl.Invoke(delegate() { MyMethod(this, new MyEventArgs(someParameter)); }); 

ここで、someParameterはこのメソッドに対してローカルです

上記の場合、コンパイラエラーが発生します。

デリゲート型ではないため、匿名メソッドを型 'System.Delegate'に変換できません

回答:


221

Invoke/ BeginInvokeDelegate(型付きデリゲートではなく)受け入れるので、作成するデリゲートのタイプをコンパイラーに通知する必要があります。MethodInvoker(2.0)またはAction(3.5)が一般的な選択肢です(同じ署名があることに注意してください)。そのようです:

control.Invoke((MethodInvoker) delegate {this.Text = "Hi";});

パラメータを渡す必要がある場合は、「キャプチャされた変数」がその方法です。

string message = "Hi";
control.Invoke((MethodInvoker) delegate {this.Text = message;});

(注意:キャプチャasyncを使用する場合は少し注意する必要がありますが、同期は問題ありません。つまり、上記は問題ありません)

別のオプションは拡張メソッドを書くことです:

public static void Invoke(this Control control, Action action)
{
    control.Invoke((Delegate)action);
}

次に:

this.Invoke(delegate { this.Text = "hi"; });
// or since we are using C# 3.0
this.Invoke(() => { this.Text = "hi"; });

もちろん、同じことをBeginInvoke次のように行うこともできます。

public static void BeginInvoke(this Control control, Action action)
{
    control.BeginInvoke((Delegate)action);
}

C#3.0を使用できない場合は、通常のインスタンスメソッドを使用して、おそらくForm基本クラスで同じことができます。


この回答の最初のソリューションにパラメーターを渡すにはどうすればよいですか?このソリューションを意味しました:control.Invoke((MethodInvoker)delegate {this.Text = "Hi";});
uzay95 2009年

1
ExtensionメソッドがActionへの明示的なキャストを行わなくても呼び出されるのはなぜですか?
P.Brian.Mackey 2013年

コンパイラは使用法からそれを推測できるからです。
RoboJ1M 2016

1
Form.Load += Loader()古いものの代わりにできることと同じですForm.Load += new EventHandler(Loader())
RoboJ1M '29 / 02/29

49

実際には、デリゲートキーワードを使用する必要はありません。パラメータとしてラムダを渡すだけです:

control.Invoke((MethodInvoker)(() => {this.Text = "Hi"; }));


13

デリゲート型を作成する必要があります。無名メソッドの作成におけるキーワード「デリゲート」は、少し誤解を招くものです。匿名デリゲートではなく匿名メソッドを作成しています。作成したメソッドはデリゲートで使用できます。このような:

myControl.Invoke(new MethodInvoker(delegate() { (MyMethod(this, new MyEventArgs(someParameter)); }));

8

完全を期すために、これはアクションメソッド/匿名メソッドの組み合わせを介して実行することもできます。

//Process is a method, invoked as a method group
Dispatcher.Current.BeginInvoke((Action) Process);
//or use an anonymous method
Dispatcher.Current.BeginInvoke((Action)delegate => {
  SomeFunc();
  SomeOtherFunc();
});

Invoke((Action) Process);最良の答えです、ありがとう!
ジンジノフ

5

メソッドから値を返す場合があるため、他の提案に問題がありました。MethodInvokerを戻り値で使用しようとすると、気に入らないようです。だから私が使用する解決策は次のようなものです(これをもっと簡潔にする方法を聞いてとても嬉しいです-私はc#.net 2.0を使用しています):

    // Create delegates for the different return types needed.
    private delegate void VoidDelegate();
    private delegate Boolean ReturnBooleanDelegate();
    private delegate Hashtable ReturnHashtableDelegate();

    // Now use the delegates and the delegate() keyword to create 
    // an anonymous method as required

    // Here a case where there's no value returned:
    public void SetTitle(string title)
    {
        myWindow.Invoke(new VoidDelegate(delegate()
        {
            myWindow.Text = title;
        }));
    }

    // Here's an example of a value being returned
    public Hashtable CurrentlyLoadedDocs()
    {
        return (Hashtable)myWindow.Invoke(new ReturnHashtableDelegate(delegate()
        {
            return myWindow.CurrentlyLoadedDocs;
        }));
    }

1

MethodInvokerの代わりにActionを使用したいのですが、短くてすっきりしています。

Invoke((Action)(() => {
    DoSomething();
}));

// OR

Invoke((Action)delegate {
    DoSomething();
});

例えば。

// Thread-safe update on a form control
public void DisplayResult(string text){
    if (txtResult.InvokeRequired){
        txtResult.Invoke((Action)delegate {
            DisplayResult(text);
        });
        return;
    }

    txtResult.Text += text + "\r\n";
}

0

なぜこれがコンパイラに影響を与えるのか理解できませんでしたが、これで十分です。

public static class ControlExtensions
{
    public static void Invoke(this Control control, Action action)
    {
        control.Invoke(action);
    }
}

おまけ:Control.Invokeバックグラウンドスレッドから使用している場合、コントロールのテキスト/進行状況/有効な状態を更新していて、コントロールが既に破棄されているかどうかは気にしない可能性が高いため、いくつかのエラー処理を追加します。

public static class ControlExtensions
{
    public static void Invoke(this Control control, Action action)
    {
        try
        {
            if (!control.IsDisposed) control.Invoke(action);
        }
        catch (ObjectDisposedException) { }
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.