131

Take the method System.Windows.Forms.Control.Invoke(Delegate method)

Why does this give a compile time error:

string str = "woop";
Invoke(() => this.Text = str);
// Error: Cannot convert lambda expression to type 'System.Delegate'
// because it is not a delegate type

Yet this works fine:

string str = "woop";
Invoke((Action)(() => this.Text = str));

When the method expects a plain Delegate?

Even Mien
  • 44,393
  • 43
  • 115
  • 119
xyz
  • 27,223
  • 29
  • 105
  • 125

9 Answers9

129

A lambda expression can either be converted to a delegate type or an expression tree - but it has to know which delegate type. Just knowing the signature isn't enough. For instance, suppose I have:

public delegate void Action1();
public delegate void Action2();

...

Delegate x = () => Console.WriteLine("hi");

What would you expect the concrete type of the object referred to by x to be? Yes, the compiler could generate a new delegate type with an appropriate signature, but that's rarely useful and you end up with less opportunity for error checking.

If you want to make it easy to call Control.Invoke with an Action the easiest thing to do is add an extension method to Control:

public static void Invoke(this Control control, Action action)
{
    control.Invoke((Delegate) action);
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    Thanks - I updated the question because I think untyped was the wrong term to use. – xyz Jan 04 '09 at 20:14
  • 1
    That is a very elegant and mature solution. I'd probably call it "InvokeAction" so that the name suggests what we're actually invoking (instead of a generic delegate) but it certainly works for me :) – Matthias Hryniszak Oct 06 '10 at 22:23
  • 7
    I disagree that it's "rarely useful and ...". In the case of calling Begin/Invoke with a lambda you certainly don't care if the delegate type is auto-generated, we just want to get the call made. In what situation would a method that accepts a Delegate (the base type) care what the concrete type is? Also, what is the purpose of the extension method? It doesn't make anything easier. – Tergiver Jan 07 '11 at 15:07
  • 1
    @Tergiver: The extension method certainly *does* make things easier. You can just call `control.Invoke(() => DoStuff)` because there *is* a conversion from the lambda expression to `Action`. Doesn't that do exactly what we want? As whether the "autogenerated" delegate is useful - I'd argue that the problem here is that `Delegate` really isn't appropriate in the first place. What should `Control.Invoke` pass in if you give it a delegate with 10 parameters? It was the best option available in .NET 1, but with generics there are better approaches IMO. – Jon Skeet Jan 07 '11 at 15:12
  • 5
    Ah! I added the extension method and tried `Invoke(()=>DoStuff)` and still got the error. The problem was that I used the implicit 'this'. To get it to work from within a Control member you have to be explicit: `this.Invoke(()=>DoStuff)`. – Tergiver Jan 07 '11 at 15:23
  • 2
    For anyone else reading this, I think the question&answers to [C#: Automating the InvokeRequired code pattern](http://stackoverflow.com/a/2367763/209259) are very helpful. – Erik Philips Jan 09 '13 at 01:12
  • Thats a good answer! Similarly you can't cast an anonymous delegate directly to LambdaExpression, instead one has to cast with the exact expression with types specified – nawfal Apr 27 '13 at 00:23
35

Tired of casting lambdas over and over?

public sealed class Lambda<T>
{
    public static Func<T, T> Cast = x => x;
}

public class Example
{
    public void Run()
    {
        // Declare
        var c = Lambda<Func<int, string>>.Cast;
        // Use
        var f1 = c(x => x.ToString());
        var f2 = c(x => "Hello!");
        var f3 = c(x => (x + x).ToString());
    }
}
  • 3
    That's a beautiful use of generics. – Peter Wone Nov 10 '11 at 00:15
  • 2
    I'll have to admit, this took me awhile to figure out why it worked. Brilliant. Too bad I have no use for it right now. – William Dec 18 '12 at 19:26
  • 2
    Can you please explain the usage of this? Its difficult for me to comprehend this? Thanks a lot. – shahkalpesh Jan 23 '13 at 19:33
  • Its to ever read this let alone say it but i think i prefer this answer to Jon Skeet's! – Pogrindis Sep 30 '13 at 15:17
  • @shahkalpesh its not very complex. See it this way, the `Lambda` class has an identity conversion method called `Cast`, which returns whatever is passed (`Func`). Now the `Lambda` is declared as `Lambda>` which means if you pass a `Func` to `Cast` method, it returns `Func` back, since `T` in this case is `Func`. – nawfal Jan 16 '14 at 17:23
  • So now variable `c` is the delegate to the `Cast` function. It takes input of `T` which is `Func`, so those are passed as arguments in the form of lambda (`c(.. => ...)`) which returns the same back which `f1`, `f2` etc knows. Basically you're relying on compiler's inferring mechanism. – nawfal Jan 16 '14 at 17:24
12

Nine tenths of the time people get this because they are trying to marshal onto the UI thread. Here's the lazy way:

static void UI(Action action) 
{ 
  System.Windows.Threading.Dispatcher.CurrentDispatcher.BeginInvoke(action); 
}

Now that it's typed, the problem goes away (qv Skeet's anwer) and we have this very succinct syntax:

int foo = 5;
public void SomeMethod()
{
  var bar = "a string";
  UI(() =>
  {
    //lifting is marvellous, anything in scope where the lambda
    //expression is defined is available to the asynch code
    someTextBlock.Text = string.Format("{0} = {1}", foo, bar);        
  });
}

For bonus points here's another tip. You wouldn't do this for UI stuff but in cases where you need SomeMethod to block till it completes (eg request/response I/O, waiting for the response) use a WaitHandle (qv msdn WaitAll, WaitAny, WaitOne).

Note that AutoResetEvent is a WaitHandle derivative.

public void BlockingMethod()
{
  AutoResetEvent are = new AutoResetEvent(false);
  ThreadPool.QueueUserWorkItem ((state) =>
  {
    //do asynch stuff        
    are.Set();
  });      
  are.WaitOne(); //don't exit till asynch stuff finishes
}

And a final tip because things can get tangled: WaitHandles stall the thread. This is what they're supposed to do. If you try to marshal onto the UI thread while you have it stalled, your app will hang. In this case (a) some serious refactoring is in order, and (b) as a temporary hack you can wait like this:

  bool wait = true;
  ThreadPool.QueueUserWorkItem ((state) =>
  {
    //do asynch stuff        
    wait = false;
  });
  while (wait) Thread.Sleep(100);
Peter Wone
  • 17,965
  • 12
  • 82
  • 134
  • 3
    I find it fascinating that people have the cheek to vote down an answer merely because they personally don't find it appealing. If it's *wrong* and you know this, then say what's wrong with it. If you can't do so, then you have no basis for a downvote. If it's epically wrong then say something like "Baloney. See [correct response]" or perhaps "Not a recommended solution, see [better stuff]" – Peter Wone Aug 01 '12 at 01:29
  • 1
    Yes, I am the frankenthreadstress; but anyway I have no idea why it was voted down; although I haven't used the actual code, I thought this was a nice quick intro to UI cross-thread invokes, and it has some things I hadn't really thought of so kudos, definitely +1 for going above and beyond. :) I mean, you gave a nice quick method for making delegate invokes; you give an option for calls which must be waited on; and you follow it up with a nice quick way for someone who is stuck in UI Thread Hell to get a bit of control back. Fine answer, I am gonna say +<3 as well. :) – shelleybutterfly Nov 09 '12 at 10:59
  • `System.Windows.Threading.Dispatcher.CurrentDispatcher` will return the CURRENT thread's dispatcher -- i.e. if you call this method from a thread that is not the UI thread, the code will not be run on the UI thread. – BrainSlugs83 May 25 '18 at 22:35
  • @BrainSlugs83 good point, probably the best thing is for an app to capture a reference to the UI thread dispatcher on and put it somewhere globally accessible. I'm amazed it took this long for someone to notice that! – Peter Wone May 27 '18 at 10:58
4

Peter Wone. you are da man. Taking your concept a bit further, I came up with these two functions.

private void UIA(Action action) {this.Invoke(action);}
private T UIF<T>(Func<T> func) {return (T)this.Invoke(func);}

I place these two functions into my Form app, and I can make calls from background workers like this

int row = 5;
string ip = UIF<string>(() => this.GetIp(row));
bool r = GoPingIt(ip);
UIA(() => this.SetPing(i, r));

Maybe a bit lazy, but i don't have to setup worker done functions, which comes in super handy in cases such as this

private void Ping_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
  int count = this.dg.Rows.Count;
  System.Threading.Tasks.Parallel.For(0, count, i => 
  {
    string ip = UIF<string>(() => this.GetIp(i));
    bool r = GoPingIt(ip);
    UIA(() => this.SetPing(i, r));
  });
  UIA(() => SetAllControlsEnabled(true));
}

Essentially, get some ip addresses from a gui DataGridView, ping them, set the resulting icons to green or red, and reenable buttons on the form. Yes, it is a "parallel.for" in a backgroundworker. Yes it is a LOT of invoking overhead, but its negligible for short lists, and much more compact code.

rocketsarefast
  • 4,072
  • 1
  • 24
  • 18
1

I tried to build this upon @Andrey Naumov's answer. May be this is a slight improvement.

public sealed class Lambda<S>
{
    public static Func<S, T> CreateFunc<T>(Func<S, T> func)
    {
        return func;
    }

    public static Expression<Func<S, T>> CreateExpression<T>(Expression<Func<S, T>> expression)
    {
        return expression;
    }

    public Func<S, T> Func<T>(Func<S, T> func)
    {
        return func;
    }

    public Expression<Func<S, T>> Expression<T>(Expression<Func<S, T>> expression)
    {
        return expression;
    }
}

Where type parameter S is the formal parameter (the input parameter, which is minimum required to infer rest of the types). Now you can call it like:

var l = new Lambda<int>();
var d1 = l.Func(x => x.ToString());
var e1 = l.Expression(x => "Hello!");
var d2 = l.Func(x => x + x);

//or if you have only one lambda, consider a static overload
var e2 = Lambda<int>.CreateExpression(x => "Hello!");

You can have additional overloads for Action<S> and Expression<Action<S>> similarly in the same class. For other built in delegate and expression types, you will have to write separate classes like Lambda, Lambda<S, T>, Lambda<S, T, U> etc.

Advantage of this I see over the original approach:

  1. One less type specification (only the formal parameter needs to be specified).

  2. Which gives you the freedom to use it against any Func<int, T>, not just when T is say, string, as shown in examples.

  3. Supports expressions straight away. In the earlier approach you will have to specify types again, like:

    var e = Lambda<Expression<Func<int, string>>>.Cast(x => "Hello!");
    
    //or in case 'Cast' is an instance member on non-generic 'Lambda' class:
    var e = lambda.Cast<Expression<Func<int, string>>>(x => "Hello!");
    

    for expressions.

  4. Extending the class for other delegate (and expression) types is similarly cumbersome like above.

    var e = Lambda<Action<int>>.Cast(x => x.ToString());
    
    //or for Expression<Action<T>> if 'Cast' is an instance member on non-generic 'Lambda' class:
    var e = lambda.Cast<Expression<Action<int>>>(x => x.ToString());
    

In my approach you have to declare types only once (that too one less for Funcs).


One another way to implement Andrey's answer is like not going fully generic

public sealed class Lambda<T>
{
    public static Func<Func<T, object>, Func<T, object>> Func = x => x;
    public static Func<Expression<Func<T, object>>, Expression<Func<T, object>>> Expression = x => x;
}

So things reduce to:

var l = Lambda<int>.Expression;
var e1 = l(x => x.ToString());
var e2 = l(x => "Hello!");
var e3 = l(x => x + x);

That's even less typing, but you lose certain type safety, and imo, this is not worth it.

Community
  • 1
  • 1
nawfal
  • 70,104
  • 56
  • 326
  • 368
1

Bit late to the party but you can also cast like this

this.BeginInvoke((Action)delegate {
    // do awesome stuff
});
Tien Dinh
  • 1,037
  • 7
  • 12
0
 this.Dispatcher.Invoke((Action)(() => { textBox1.Text = "Test 123"; }));
Narottam Goyal
  • 3,534
  • 27
  • 26
0

Playing with XUnit and Fluent Assertions it was possible to use this inline capability in a way I find really cool.

Before

[Fact]
public void Pass_Open_Connection_Without_Provider()
{
    Action action = () => {
        using (var c = DbProviderFactories.GetFactory("MySql.Data.MySqlClient").CreateConnection())
        {
            c.ConnectionString = "<xxx>";
            c.Open();
        }
    };

    action.Should().Throw<Exception>().WithMessage("xxx");
}

After

[Fact]
public void Pass_Open_Connection_Without_Provider()
{
    ((Action)(() => {
        using (var c = DbProviderFactories.GetFactory("<provider>").CreateConnection())
        {
            c.ConnectionString = "<connection>";
            c.Open();
        }
    })).Should().Throw<Exception>().WithMessage("Unable to find the requested .Net Framework Data Provider.  It may not be installed.");
}
0

Other answers were correct at the time they were written, but starting from C# 10.0 (from 2021), the compiler can infer a suitable delegate type (like some Func<...>, Action<...> or generated delegate type) in such cases.

See C# 10 Features - Lambda improvements.

string str = "woop";
Invoke(() => this.Text = str);   // OK in C# 10.0, in this case 'Func<string>' is picked
string str = "woop";
Invoke(() => { this.Text = str; });   // OK in C# 10.0, in this case 'Action' is picked

Comments assume the signature Invoke(Delegate method) as in your question. Of course if the method wants a particular (not abstract) delegate type, C# will attempt to convert the lambda into that one, as was also the case before C# 10.0.

Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181