Анонимный метод как параметр для BeginInvoke?

Почему вы не можете передать анонимный метод в качестве параметра методу BeginInvoke? У меня такой код:

private delegate void CfgMnMnuDlg(DIServer svr);
private void ConfigureMainMenu(DIServer server,)
{
    MenuStrip mnMnu = PresenterView.MainMenu;
    if (mnMnu.InvokeRequired)
    {
        mnMnu.BeginInvoke((CfgMnMnuDlg)ConfigureMainMenu, 
                            new object[] { server});
    }
    else
    {
        // Do actual work here
    }
}

Я пытаюсь не объявлять делегата. Почему я не могу вместо этого написать что-то подобное? Или я могу и просто не могу понять правильный синтаксис? Нижеприведенное в настоящее время генерирует:

Тип аргумента «Анонимный метод» не может быть назначен типу параметра «System.Delegate»

Хорошо, конечно, это правильно, но есть ли другой синтаксис, который я могу использовать для этого (избегайте необходимости объявлять отдельный делегат, чтобы использовать BeginInvoke()?

(Возможность сделать это прекрасно вписывалась бы в концепцию использования анонимных методов / lamdas вместо явных делегатов, которые так чисто работают повсюду.)

private void ConfigureMainMenu(DIServer server,)
{
    MenuStrip mnMnu = PresenterView.MainMenu;
    if (mnMnu.InvokeRequired)
    {
        mnMnu.BeginInvoke(  //  pass anonymous method instead ?
             delegate(DIServer svr) { ConfigureMainMenu(server);},     
             new object[] { server});
    }
    else
    {
        // Do actual work here
    }
}

person Charles Bretana    schedule 17.06.2009    source источник
comment
Хороший пост по теме: smehrozalam.wordpress.com/2009/11/24/   -  person Jeff B    schedule 19.02.2015


Ответы (6)


Попробуй это:

control.BeginInvoke((MethodInvoker) delegate { /* method details */ });

Or:

private void ConfigureMainMenu(DIServer server)
{
    if (control.InvokeRequired)
    {
        control.BeginInvoke(new Action<DIServer >(ConfigureMainMenu), server);
    }
    else
    {
        /* do work */
    }
}

Or:

private void ConfigureMainMenu(DIServer server)
{
    MenuStrip mnMnu = PresenterView.MainMenu;
    if (mnMnu.InvokeRequired)
    {
        // Private variable
        _methodInvoker = new MethodInvoker((Action)(() => ConfigureMainMenu(server)));
        _methodInvoker.BeginInvoke(new AsyncCallback(ProcessEnded), null); // Call _methodInvoker.EndInvoke in ProcessEnded
    }
    else
    {
        /* do work */
    }
}
person ilitirit    schedule 17.06.2009
comment
из какой библиотеки MethodInvoker? используя System.? - person apandit; 17.06.2009
comment
@ilitirit: Компилируется нормально, но только если я включу в вызов параметры метода: mnMnu.BeginInvoke ((MethodInvoker) delegate (DIServer svr) {ConfigureMainMenu (server);}, new object [] {server}); Итак, теперь я дважды передаю сервер параметров метода .. Один раз внутри метода anon и один раз в параметре object [] для Begin Invoke ... Как это работает? - person Charles Bretana; 17.06.2009
comment
@apandit: System.Windows.Forms @Charles: вы передадите его дважды, независимо от того, какой метод вы используете из-за вызова делегата. - person ilitirit; 17.06.2009
comment
@Ilitrit, спасибо, Action ‹param› () отлично работал с моими экземплярами делегатов, которые принимают только один параметр, и после некоторого исследования я теперь знаю, что Action ‹› () в CLR 3.x также существует в версиях, которые принимают 2, 3, параметры и т. Д. Очень хорошо ... Этот конкретный концерт все еще использует CLR 2.0, но 80% делегатов, которые я использую, принимают только 1 параметр ... - person Charles Bretana; 17.06.2009

У вас должно получиться написать что-то вроде этого:

private void ConfigureMainMenu(DIServer server,)
{
    MenuStrip mnMnu = PresenterView.MainMenu;
    if (mnMnu.InvokeRequired)
    {
        mnMnu.BeginInvoke(new Action<DIServer>(ConfigureMainMenu), 
                            new object[] { server});
    }
    else
    {
        // Do actual work here
    }
}
person Jake    schedule 17.06.2009

Вы могли бы написать метод расширения, который обернул бы анонимные методы и даже позаботился о семантике InvokeRequired:

public static void InvokeAction(this Control ctl, Action a)
{
    if (!ctl.InvokeRequired)
    {
        a();
    }
    else
    {
        ctl.BeginInvoke(new MethodInvoker(a));
    }
}

Это позволит вам:

control.InvokeAction(delegate() { ConfigureMainMenu(server); });
person Jason    schedule 17.06.2009

Вы можете сделать это одним методом, вызвав себя:

  ClassData updData =  new ClassData();

  this.BeginInvoke(new Action<ClassData>(FillCurve),
                           new object[] { updData });

...

public void FillCurve(ClassData updData)
{
 ...
}
person RckLN    schedule 24.09.2014

Для полностью анонимных методов с ограниченным количеством параметров:

Func<int, int?> caller = new Func<int, int?>((int param1) =>
   {
      return null;
   });

caller.BeginInvoke(7, new AsyncCallback((IAsyncResult ar) =>
{
   AsyncResult result = (AsyncResult)ar;
   Func<int, int?> action = (Func<int, int?>)result.AsyncDelegate;
   action.EndInvoke(ar);
}), null);

При необходимости вы можете использовать один из других типов делегатов Func.

person Community    schedule 25.09.2009

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


// Fails -- cannot convert lamda to System.Delegate
mnMnu.BeginInvoke( (DIServer svr)=> {ConfigureMainMenu(server);}, new object[] server);
// Fails -- cannot convert anonymous method to System.Delegate
mnMnu.BeginInvoke( new delegate(DIServer svr){ConfigureMainMenu(server);}, new object[] server);

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

РЕДАКТИРОВАТЬ: Оказывается, я ошибаюсь. Приведенный ниже ответ methodinvoker работает. См. Эту страницу

person apandit    schedule 17.06.2009
comment
ах, спасибо за попытку ... ничего страшного, просто подумал, что это должно быть возможно ... это вписывается в концепцию использования анонимных методов / ламд вместо явных делегатов, которые так чисто работают везде. - person Charles Bretana; 17.06.2009