Reputation: 4071
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.
Upvotes: 11
Views: 9512
Reputation: 421
Using C# 10 and Visual Studio 2022 you don't need the explicit cast anymore (natural function type).
Upvotes: 3
Reputation: 171246
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.
Upvotes: 3