2

So here I'm trying to pass a method with a random signature to Foo method. But without any luck.
The thing is that I can pass any action. But on a method.
Any help?

class Bar
{
    void M1(int a) { }
    void M2(string a, int b) { }

    Action<string, int, bool> A1 = (s, i, b) => {};
    Action<int, float> A2 = (i, f) => {};

    void Foo(Delegate f) {}

    void Test()
    {
        Foo(A1);
        Foo(A2);
        // Foo(M1); // nope
        // Foo(M2); // no way
    }
}

PS. I'm trying to get this working under Unity3d's Mono.

2
  • 1
    This is not specific to unity3d or mono, it's just part of the language. M1 and M2 are "method groups" not delegates. A method group can be converted to any compatible delegate type, and the the compiler refuses to pick one out of the air (like the Action or Func types). Commented Nov 21, 2016 at 9:05
  • Yeah, I know. I just mentioned it in case someone suggests the solution based on unique features of C# 3.0+. Commented Nov 22, 2016 at 8:37

1 Answer 1

4

You have to cast to concrete delegate type to do that, like this:

void Test()
{
    Foo(A1);
    Foo(A2);
    Foo((Action<int>) M1);
    Foo((Action<string, int>)M2); 
}

The reason for this is M1 and M2 are what is called method groups. That just means they refer to one or more methods. Why it can be more than one? Because you might have multiple methods with name M1, each of which accepts different set of arguments. But, even if you have just one overload, like in your case, there might be multiple delegate types compatible with that overload signature (that might be Action<int> or YourDelegateType which is declared as delegate void YourDelegateType(int arg), or whatever else).

That is why there is no implicit conversion from method group to delegate, and you have to cast method group to specific delegate type explicitly.

Sign up to request clarification or add additional context in comments.

4 Comments

One thing is that multiple overloads may exist. But in this case, each of the names M1 and M2 has only one overload. Another thing is that multiple compatible concrete delegate types may exist. For example, with void M3(object a, int b) { } (just this single overload), the call Foo(M3); could stand for either Foo((Action<object, int>)M3); or Foo((EventHandler<int>)M3);. Or even Foo((MyDel)M3); where MyDel is some type you create yourself. The Action<,> does not have a special status in C#, so the compiler will not pick Action<,> "out of nothing".
Also, because co- and contravariance are possible with method group conversions, you can sometimes use another set of type parameters. Continuing my example from before, both Foo((Action<object, int>)M3); and Foo((Action<Uri, int>)M3); are possible.
Good points indeed. With that it's clear that there is no way to convert method group to delegate without explicitly choosing delegate type, even if just one overload exists.
Thanks for the explanation and solution. It fully satisfies me.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.