Анонимный метод в вызове Invoke

Имея немного проблем с синтаксисом, когда мы хотим анонимно вызвать делегат в Control.Invoke.

Мы попробовали несколько разных подходов, все безрезультатно.

Например:

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

где someParameter является локальным для этого метода

Приведенное выше приведет к ошибке компилятора:

Невозможно преобразовать анонимный метод для ввода "System.Delegate", потому что это не тип делегата

Ответ 1

Поскольку Invoke/BeginInvoke принимает Delegate (а не типизированный делегат), вам нужно сообщить компилятору, какой тип делегата создать; 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);
}

Если вы не можете использовать С# 3.0, вы можете сделать то же самое с обычным методом экземпляра, предположительно в базовом классе Form.

Ответ 2

На самом деле вам не нужно использовать ключевое слово delegate. Просто передайте lambda в качестве параметра:

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

Ответ 3

myControl.Invoke(new MethodInvoker(delegate() {...}))

Ответ 4

Вам нужно создать тип делегата. Ключевое слово "делегат" в создании анонимного метода немного вводит в заблуждение. Вы не создаете анонимного делегата, а анонимный метод. Созданный вами метод может использоваться в делегате. Вот так:

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

Ответ 5

Для полноты этого также можно выполнить с помощью комбинации метода действий/анонимного метода:

//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();
});

Ответ 6

У меня были проблемы с другими предложениями, потому что я хочу иногда возвращать значения из моих методов. Если вы попытаетесь использовать MethodInvoker с возвращаемыми значениями, ему это не похоже. Таким образом, решение, которое я использую, похоже на это (очень рад услышать способ сделать это более кратким - я использую С#.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 no value returned:
    public void SetTitle(string title)
    {
        myWindow.Invoke(new VoidDelegate(delegate()
        {
            myWindow.Text = title;
        }));
    }

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