【问题标题】:Anonymous method as parameter to BeginInvoke?匿名方法作为 BeginInvoke 的参数?
【发布时间】:2010-11-03 16:39:02
【问题描述】:

为什么不能将匿名方法作为参数传递给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
    }
}

【问题讨论】:

标签: c# delegates anonymous-methods begininvoke


【解决方案1】:

我尝试了很多不同的方法,但都没有奏效。即...

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

所以,简短的回答是否定的。您可以在给定的上下文中创建简短的助手委托,并使用 lambda 使其更整洁,但仅此而已。

编辑:原来我错了。下面的方法调用者答案有效。 看到这个page

【讨论】:

  • 嗯,谢谢你的尝试......没什么大不了的,只是认为这个“应该”是可能的......它符合使用匿名方法/ lamdas 代替的概念显式委托,在其他任何地方都能如此干净地工作。
【解决方案2】:

试试这个:

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

或者:

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

或者:

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 */
    }
}

【讨论】:

  • MethodInvoker 来自哪个库?使用系统。?
  • @ilitirit:编译正常,但前提是我在调用中包含方法参数: mnMnu.BeginInvoke( (MethodInvoker)delegate(DIServer svr) { ConfigureMainMenu(server);}, new object[] { 服务器});所以现在我将方法参数“server”传递了两次。一次是在 anon 方法中,一次是在 object[] 参数中以 Begin Invoke ......这如何工作?
  • @apandit: System.Windows.Forms @Charles: 由于委托调用,无论您使用哪种方法,您都会“两次”传递它。
  • @Ilitrit,谢谢,Action () 非常适合我的委托实例,它只接受一个参数,经过一些研究,我现在知道 CLR 3.x 中的 Action()也存在于采用 2,3、参数等的版本中......非常 kewl.. 这个特殊的演出仍在使用 CLR 2.0,但我使用的 80% 的代表只采用 1 个参数......
【解决方案3】:

你应该可以这样写:

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

【讨论】:

    【解决方案4】:

    您可以编写一个封装匿名方法的扩展方法,甚至处理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); });
    

    【讨论】:

      【解决方案5】:

      对于参数数量有限的完全匿名方法:

      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 委托类型之一。

      【讨论】:

        【解决方案6】:

        您可以通过调用自己在单个方法中执行此操作:

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

        ...

        public void FillCurve(ClassData updData)
        {
         ...
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-03-30
          • 2013-02-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-05-16
          • 2020-06-05
          相关资源
          最近更新 更多