I'm working on a Windows Forms application, and it contains custom controls with methods that can potentially be called from threads other than the UI thread. So these methods therefore look a bit like this to prevent exceptions:
public void DoSomeStuff()
{
if (InvokeRequired)
{
Invoke((Action)DoSomeStuff);
}
else
{
// Actually do some stuff.
}
}
The explicit cast of the method group DoSomeStuff
to an Action
caught my attention, and so I've been looking into delegates and other related subjects more deeply than I have before.
Although I've seen some related questions here, I haven't been able to find exactly the answer to mine, which is:
Why does the method group DoSomeStuff
require explicit casting to an Action
in this case?
If I remove the cast, then I get two errors:
Error 102 Argument 1: cannot convert from 'method group' to 'System.Delegate'
Error 101 The best overloaded method match for 'System.Windows.Forms.Control.Invoke(System.Delegate, params object[])' has some invalid arguments
The fact that the compiler is apparently confused about which overload of Invoke
to use seems like a pretty big hint, but I'm still not sure about why exactly it can't figure that out. I would expect the compiler to deduce that the first overload of Invoke
, which takes a single Delegate
argument, is the one that should be used.
I would expect that because there is no problem if the code is written like this:
Action a = DoSomeStuff;
Invoke(a);
The method group DoSomeStuff
can be implicitly converted to the Action
delegate type, and Action
derives (technically?) from System.Delegate
, so Invoke
can handle the argument a
without any trouble. But then why can't the implicit conversion be done by the compiler when I try to pass DoSomeStuff
as the argument directly? To be honest I'm not convinced by my own logic here, but I still am not sure what I'm missing.
The problem is not that the compiler has trouble picking an overload. The "best match" overload is the one you want but it has invalid arguments. The C# language does not define any implicit conversion from method group (DoSomeStuff
) to System.Delegate
.
You might say that the compiler should just pick one of the Action
/Func
types and this has been requested as a language feature. Right now this is not part of C#. (I don't know why; I hope the language request goes through.)
System.Windows.Forms.Control.Invoke
was created in .NET 1.0. Today, one would use the following signatures:
void Invoke(Action action);
Task InvokeAsync(Action action);
And it would simply work.
Try to make the migration to await
and this stops being a concern.
Using C# 10 and Visual Studio 2022 you don't need the explicit cast anymore (natural function type).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With