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



возникли некоторые проблемы с синтаксисом, где мы хотим вызвать делегат анонимно в элементе управления.Взывать.



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



например:



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


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



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




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


511   7  

7 ответов:

, потому что 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;});

(предостережение: вы должны быть немного осторожны при использовании захватов асинхронные, а синхронизация это нормально - т. е. выше это нормально)

другой вариант-написать метод расширения:

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 базового класса.

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

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

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

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

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

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

У меня были проблемы с другими предложениями, потому что я хочу иногда вернуть ценности из моих методов. Если вы пытаетесь использовать 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;
        }));
    }

Я никогда не понимал, почему это имеет значение для компилятора, но этого достаточно.

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) { }
    }
}

Comments

    Ничего не найдено.