Implicitly convert method group to Delegate (for argument of Control.Invoke)
Asked Answered
R

2

11

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.

Razorback answered 17/7, 2015 at 10:34 Comment(0)
M
3

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.

Mansuetude answered 17/7, 2015 at 10:59 Comment(4)
> You might say that the compiler should just pick one of the Action/Func types and this has been requested as a language feature This very easily breaks down: void Foo(out string abc);Is not representable using Action or Func. If they implement Action/Func inference as a language feature that feature would be broken.Ranchod
@Ranchod with this particular signature the conversion could fail (statically). It's a rare case, I think it's fine to show an error here. Not every method can be represented as an Action/Func but 99% of them can be in practice. All delegate types should be treated structurally with implicit conversions where it makes sense.Mansuetude
I don't think it's okay. The error is shown because the feature is fundamentally broken.Ranchod
I don't quite get what you're saying here GeirGrusom. Why should the compiler not being able to infer that a method is an Action or a Func in some special cases mean that in all cases the error should be shown? By that logic, surely the implicit conversion of DoSomeStuff to an Action (in the original question) should also be an error?Razorback
R
3

Using C# 10 and Visual Studio 2022 you don't need the explicit cast anymore (natural function type).

Refraction answered 17/3, 2022 at 14:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.