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?
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:
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 anAction
the easiest thing to do is add an extension method to Control:Tired of casting lambdas over and over?
Bit late to the party but you can also cast like this
I tried to build this upon @Andrey Naumov's answer. May be this is a slight improvement.
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:You can have additional overloads for
Action<S>
andExpression<Action<S>>
similarly in the same class. For other built in delegate and expression types, you will have to write separate classes likeLambda
,Lambda<S, T>
,Lambda<S, T, U>
etc.Advantage of this I see over the original approach:
One less type specification (only the formal parameter needs to be specified).
Which gives you the freedom to use it against any
Func<int, T>
, not just whenT
is say,string
, as shown in examples.Supports expressions straight away. In the earlier approach you will have to specify types again, like:
for expressions.
Extending the class for other delegate (and expression) types is similarly cumbersome like above.
In my approach you have to declare types only once (that too one less for
Func
s).One another way to implement Andrey's answer is like not going fully generic
So things reduce to:
That's even less typing, but you lose certain type safety, and imo, this is not worth it.
Nine tenths of the time people get this because they are trying to marshal onto the UI thread. Here's the lazy way:
Now that it's typed, the problem goes away (qv Skeet's anwer) and we have this very succinct syntax:
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.
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: