Control.BeginInvoke
:
In both cases, it seems clear that the compiler has all the information it needs to infer the delegate type. Yet in neither case does the type inference seem to work:
BeginInvoke(myMethodThatTakesNoParams);
produces the compiler error
Error 105 The best overloaded method match for 'System.Windows.Forms.Control.BeginInvoke(System.Delegate)' has some invalid arguments
as does
BeginInvoke(ShowProcessErrors, new object[] { process });
Both method calls only compile if I change them to explitly create a delegate and pass that. Both of the following compile fine:
BeginInvoke(new MethodInvoker(myMethodThatTakesNoParams));
and
BeginInvoke(new ProcessErrorDelegate(ShowProcessErrors), new object[] { process });
There doesn't seem to be any obvious reason why type inference won't work here. Is there a way to call BeginInvoke
without explicitly creating a delegate?
This usually comes as a surprise to .NET programmers, the C# Language Specific in section 15.1 explains:
And of course there is no conversion of a method to a class. The first argument of BeginInvoke() must be a delegate type to keep the compiler happy. Maybe that sounds like an arbitrary limitation, it is most definitely not. A very important property of delegates is that they are type-safe. A pretty big deal in a statically typed language like C#. You can't invoke a delegate with too few arguments, or too many, or arguments of the wrong type. Checked when the delegate is created, you get a compile time error while you are still in your pajamas or the comfort of your cubicle. No surprises at runtime with your program suddenly keeling over at the most inopportune time of the day. This type checking of course cannot work for Delegate. So it is not a delegate type.
This does go wrong with Control.BeginInvoke(), it uses a back-door to get the method invoked. Kaboom when you pass
Math.Pi
instead of progress, you can't find out until you run the code. Not a pleasant exception either because it is unclear whether you got the BeginInvoke() call wrong or whether the invoked method threw an exception. Actually much more of a problem with Invoke().Anyhoo, gotta give the compiler a delegate, more than one way to do that:
The venerable anonymous method syntax still works pretty well in this context:
You already found MethodInvoker, I usually go for Action since it is shorter:
And you can of course always keep the compiler happy with an extension method:
with:
The issue is that
myMethodThatTakesNoParams
isn't really a delegate but a so-called "method group" by the compiler. A method group isn't a real type in the CLR. It must be converted to delegate type to be used. When you use a method group like this:The compiler recognizes that you want to convert the method group to a delegate and inserts the conversion for you. It produces IL that effectively says:
When you say:
The compiler doesn't really know what to do. It could theoretically pick any compatible delegate type for you, but C#, in general, does not insert types you did not use into expressions. Since it does not know what delegate you want the method group converted to, the compiler produces an error.
I used variable assignment in my examples, but the same logic applies for parameters to methods.
A work around would be to write your own extension method that has a specific delegate type in it: