Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 508
Adam Goodwin Avatar asked Jul 17 '15 10:07

Adam Goodwin


2 Answers

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.

like image 161
usr Avatar answered Nov 15 '22 08:11

usr


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

like image 45
thomas.s Avatar answered Nov 15 '22 07:11

thomas.s