19

Why can't you pass an anonymous method as a parameter to the BeginInvoke method? I have the following code:

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

I'm trying to avoid declaring the delegate. Why can't I write something like the below instead? Or can I, and I just can't figure out the correct syntax? The below currently generates an:

Argument type 'Anonymous method' is not assignable to parameter type 'System.Delegate'

Ok, that's right of course, but is there some other syntax I can use to do this (avoid having to declare a separate delegate in order to use BeginInvoke()?

(Being able to do this would fit in neatly with the concept of using anon methods/lamdas in place of explicit delegates which works so cleanly everywhere else.)

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
    }
}
Michał Powaga
  • 22,561
  • 8
  • 51
  • 62
Charles Bretana
  • 143,358
  • 22
  • 150
  • 216
  • Good related post: https://smehrozalam.wordpress.com/2009/11/24/control-invoke-and-begininvoke-using-lamba-and-anonymous-delegates/ – Jeff B Feb 19 '15 at 15:13

6 Answers6

36

Try this:

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 */
    }
}
Michał Powaga
  • 22,561
  • 8
  • 51
  • 62
ilitirit
  • 16,016
  • 18
  • 72
  • 111
  • what library is MethodInvoker from? using System.? – apandit Jun 17 '09 at 15:05
  • @ilitirit: That compiles ok, but only if I include method params in the call: mnMnu.BeginInvoke( (MethodInvoker)delegate(DIServer svr) { ConfigureMainMenu(server);}, new object[] { server}); So now I am passing the method parameter "server" twice.. Once inside of the anon method, and once in object[] param to Begin Invoke... Hows that working ? – Charles Bretana Jun 17 '09 at 15:10
  • @apandit: System.Windows.Forms @Charles: You will pass it "twice" no matter which method you use because of the delegate invocation. – ilitirit Jun 17 '09 at 15:18
  • @Ilitrit, Thanks, Action () worked great for my delegate instances that take only one parameter, and after some research, I now know that Action<>() in CLR 3.x also exists in versions that take 2,3, parameters, etc... Very kewl.. This particular gig is still using CLR 2.0, but 80% of the delegates I am using take only 1 param... – Charles Bretana Jun 17 '09 at 15:42
2

You should be able to write something like this:

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
    }
}
Jake
  • 3,427
  • 2
  • 28
  • 23
1

You could write an extension method that would wrap anonymous methods, and even take care of the InvokeRequired semantics:

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

This would allow you to do:

control.InvokeAction(delegate() { ConfigureMainMenu(server); });
Jason
  • 28,040
  • 10
  • 64
  • 64
1

You can do this in a single method by calling invoking yourself:

  ClassData updData =  new ClassData();

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

...

public void FillCurve(ClassData updData)
{
 ...
}
RckLN
  • 4,272
  • 4
  • 30
  • 34
0

I've tried a bunch of different methods but none work. ie...


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

So, the short answer is no. You could create short helper delegates in the given context and use lambdas to make it a bit neater but that's pretty much it.

EDIT: Turns out I'm wrong. The methodinvoker answer below works. See this page

Romano Zumbé
  • 7,893
  • 4
  • 33
  • 55
apandit
  • 3,304
  • 1
  • 26
  • 32
  • ah well, thanks for trying... not a big deal, just thought this "ought" to be possible... it would fit in with the concept of using anon methods/ lamdas in place of explicit delegates that works so cleanly everywhere else. – Charles Bretana Jun 17 '09 at 15:02
0

For completely anonymous methods with a limited number of parameters:

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

You can use one of the other Func delegate types as needed.