7
class Program
{
    public delegate void VoidMethodDelegate();
    public delegate int IntMethodDelegate();

    static void Main(string[] args)
    {
        Test(IntMethod);
        Test(VoidMethod);
    }

    static int IntMethod()
    {
        return 1;
    }

    static void VoidMethod()
    {
    }

    static void Test(VoidMethodDelegate method)
    {
    }

    static void Test(IntMethodDelegate method)
    {
    }
}

I am trying to set up an overloaded method that will take two different types of delegates. The delegates differ only by return type -- in both cases they take no input parameters. So in the example above, I would like to be able to call Test() and pass it either a method that returns void, or a method that returns int. When I compile the code above, I get these errors:

error CS0121: The call is ambiguous between the following methods or properties: 'ConsoleApplication1.Program.Test(ConsoleApplication1.Program.VoidMethodDelegate)' and 'ConsoleApplication1.Program.Test(ConsoleApplication1.Program.IntMethodDelegate)'

error CS0407: 'int ConsoleApplication1.Program.IntMethod()' has the wrong return type

error CS0121: The call is ambiguous between the following methods or properties: 'ConsoleApplication1.Program.Test(ConsoleApplication1.Program.VoidMethodDelegate)' and 'ConsoleApplication1.Program.Test(ConsoleApplication1.Program.IntMethodDelegate)'

I know I can work around the errors if I create the delegates with new instead of just passing the method directly, like this:

    static void Main(string[] args)
    {
        Test(new IntMethodDelegate(IntMethod));
        Test(new VoidMethodDelegate(VoidMethod));
    }

But that syntax is messy, and I'd prefer to be able to pass the method directly, instead of having to wrap it in a call to new. The only solution I've seen is to get rid of the overloaded version of Test() and instead use two different methods, each with a different name.

Can anyone tell me why the compiler is complaining that this is ambiguous? I don't understand whhy the compiler can't decide which of the two overloads to use.

Kyle West
  • 85
  • 3
  • possible duplicate of [Compiler Ambiguous invocation error - anonymous method and method group with Func<> or Action](http://stackoverflow.com/questions/2057146/compiler-ambiguous-invocation-error-anonymous-method-and-method-group-with-fun) – nawfal May 29 '13 at 13:05
  • Don't know how much prettier it is, but instead of `Test(new IntMethodDelegate(IntMethod));` you can use `Test((IntMethodDelegate)IntMethod);`. The conversion from a method group to a delegate type is usually implicit, but you can also use (explicit) cast syntax (and have to in this case). – Jeppe Stig Nielsen Jun 08 '13 at 17:33

1 Answers1

7

Basically this is a corollary of how overloading is performed, and how method group conversions are resolved. I can try to wade through the spec to find the exact reasons if you like, but the bad news is that's just the way it is. It's possible there's a compiler bug in this case, but it's more likely that it's just a tricky bit of the spec.

I think that this SO question may be relevant, but I haven't checked yet.

Rather than resolve it using new, I would suggest take the option of using different method names. Overloading has all kinds of sneaky corner cases - this one is at least relatively harmless in that it's causing a compile-time error rather than picking the overload you don't want at execution time. Removing overloading is often a good thing :)

EDIT: I'm pretty sure that other SO question is relevant, actually. I suggest you get yourself a cup of coffee, the C# 4 spec, and then read Eric's answer very carefully. Then change the method names so you don't have to think about it any more.

Community
  • 1
  • 1
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thanks for the link, I missed that one in my initial searches. I agree with using different named methods, that's what I'll end up doing, I just wanted to make sure I wasn't missing something obvious. – Kyle West Aug 10 '10 at 13:30