anonymous delegates in C#

49,585

Solution 1

Yes. In .NET 3.5 you can use Func and Action delegates. The Func delegates return a value, while Action delegates return void. Here is what the type names would look like:

System.Func<TReturn> // (no arg, with return value)
System.Func<T, TReturn> // (1 arg, with return value)
System.Func<T1, T2, TReturn> // (2 arg, with return value)
System.Func<T1, T2, T3, TReturn> // (3 arg, with return value)
System.Func<T1, T2, T3, T4, TReturn> // (4 arg, with return value)

System.Action // (no arg, no return value)
System.Action<T> // (1 arg, no return value)
System.Action<T1, T2> // (2 arg, no return value)
System.Action<T1, T2, T3> // (3 arg, no return value)
System.Action<T1, T2, T3, T4> // (4 arg, no return value)

I don't know why they stopped at 4 args each, but it has always been enough for me.

Solution 2

There's the Action delegate you could use, like so:

private void RefreshForm()
{
    if (InvokeRequired) Invoke(new Action(Refresh));
    else Refresh();
}

Or, with lambda syntax:

private void RefreshForm()
{
    if (InvokeRequired) Invoke((Action)(() => Refresh()));
    else Refresh();
}

Finally there's anonymous delegate syntax:

private void RefreshForm()
{
    if (InvokeRequired) Invoke((Action)(delegate { Refresh(); }));
    else Refresh();
}

Solution 3

In this specific case you can (and should) just use MethodInvoker to do this... that is why it exists.

if (InvokeRequired)
    Invoke(new MethodInvoker(Refresh));
else
    Refresh();

If you were doing something else you could, as others have answered use Func<T,...> or Action<T,...> if they fit your use case.

Solution 4

Short version:

Invoke((MethodInvoker)delegate { Refresh(); });

Then you can also drop the check of InvokeRequired; you can just call it as it is. Works also if you need to pass parameters, so there is no need for other parameter-specific delegates (works just as well with the parameter-less Action delegate as well):

private void SetControlText(Control ctl, string text)
{
    Invoke((MethodInvoker)delegate { ctl.Text = text; });
}

Solution 5

Do I really need an entire delegate dedicated just for this? aren't there any generic delegates at all?

Defining your own delegates can really make debugging easier, if only because Intellisense can tell you the names of your parameters. For example, you write a delegate like this:

public delegate int UpdateDelegate(int userID, string city, string, state, string zip);

When you use it code, .NET will inform you of the parameter names, delegate name, etc, so there's a lot of context right in the delegate definition if you aren't sure exactly how something is used.

However, if you don't mind sacrificing Intellisense, there is already a class of delegates definined in the System namespace which can be used as ad-hoc delegates:

Func<T>
Func<T, U>
Func<T, U, V>
Func<T, U, V, W>
Action, Action<T>
Action<T, U>
Action<T, U, V>
Action<T, U, V, W>

Only Action and Action exist in .NET 2.0, but its easy enough to declare a helper class with the remaining delegates you need for these kind of miscellaneous ad hoc functions.

Share:
49,585
Nefzen
Author by

Nefzen

Updated on February 07, 2020

Comments

  • Nefzen
    Nefzen over 4 years

    I can't be the only one getting tired of defining and naming a delegate for just a single call to something that requires a delegate. For example, I wanted to call .Refresh() in a form from possibly other threads, so I wrote this code:

    private void RefreshForm()
    {
        if (InvokeRequired)
            Invoke(new InvokeDelegate(Refresh));
        else
            Refresh();
    }
    

    I'm not even sure I have to, I just read enough to be scared that it won't work at some later stage.
    InvokeDelegate is actually declared in another file, but do I really need an entire delegate dedicated just for this? aren't there any generic delegates at all?
    I mean, for example, there's a Pen class, but there's also Pens.pen-of-choice so you don't have to remake the whole thing. It's not the same, but I hope you understand what I mean.

  • Matthew Vines
    Matthew Vines almost 15 years
    4 is not a concrete rule, but past that you should at least consider combining parameters in some way.
  • Brian ONeil
    Brian ONeil almost 15 years
    Why would you create an anonymous delegate just to cast it to an existing delegate type? You should just use the delegate type directly.
  • Nefzen
    Nefzen almost 15 years
    oddly, the second and third syntaxes do not work saying it cannot convert it to System.Delegate because it is not a delegate type. However, Action is most definitely what I want.
  • Brian ONeil
    Brian ONeil almost 15 years
    anonymous delegates can't be passed this way to Invoke because they are not of Type Delegate. What you wrote here doesn't even compile.
  • Fredrik Mörk
    Fredrik Mörk almost 15 years
    @Brian: you mean like this: Invoke(new MethodInvoker(delegate { ctl.Text = text; })); ? As far as I can see that produces the exact same IL code as my code above, so it's down to personal taste, I guess.
  • Erik Forbes
    Erik Forbes almost 15 years
    Heh, that's what I get for not checking before posting. I'll fix asap.
  • Nefzen
    Nefzen almost 15 years
    what is the difference between MethodInvoker and Action? Also, I am checking InvokeRequired because it seems a better practice, eg, faster.
  • Nefzen
    Nefzen almost 15 years
    oh also, isn't using Action the best practice? I mean, most efficient in space and time etc?
  • Erik Forbes
    Erik Forbes almost 15 years
    Casting the lambda and anonymous delegates to Action does the trick. Sorry for the confusion.
  • Erik Forbes
    Erik Forbes almost 15 years
    In your case, yes, I would use Action - which is why I supplied it first.
  • Nefzen
    Nefzen almost 15 years
    @Fredrik: Brian meant using new MethodInvokder(Refresh) rather than (MethodInvoker)delegate { Refresh(); }
  • Brian ONeil
    Brian ONeil almost 15 years
    if it is the same IL in the end, then I guess it is more about preference, but if the delegate exists I don't understand why you would prefer to use the anonymous syntax. Just seems more straight forward to just declare it and use it.
  • Stan R.
    Stan R. almost 15 years
    this was a very helpful post.
  • Lucas
    Lucas almost 15 years
    Use Invoke((MethodInvoker)Refresh) or Invoke(new MethodInvoker(Refresh)) instead of Invoke((MethodInvoker)delegate { Refresh(); }) ... the latter creates an additional level of indirection by creating an anonymous method which only calls Refresh(), instead of creating a delegate to Refresh() itself.
  • RichardOD
    RichardOD almost 15 years
    When I'm porting some older .NET code to 3.5 and I see a delegate I swap them out for either Func or Action.
  • Eric Lippert
    Eric Lippert almost 15 years
    The next version of the framework will include Func and Action of more than four parameters.
  • Jan Willem B
    Jan Willem B over 13 years
    This is the best solution for .NET 2.0
  • Fredrik Mörk
    Fredrik Mörk about 13 years
    @Purusartha: That sounds strange. Can you provide the code that reproduces that? Would be interesting to see so that I can correct any errors.