How does C# resolve different extension method overloads?

879 Views Asked by At

I've got a code snippet as below:

public static class M
{
    public static int Plus(this int i, int p=6)
    {
        return i + p;
    }
}
public static class N
{
    public static int Plus(this int i)
    {
        return i + 10;
    }
}
class Program
{
    static void Main()
    {
        int i = 3.Plus();
        Console.WriteLine(i);
    }
}

Run the program, it outputs "13", which indicates class N's extension method is called. Why class M's method is not matched?

Then if I remove class N, OK, class M's extension method is called, it outputs "9" as expected.

So my question is, is there a rule in C# or .net framework to determine, which extension method is to be called if multiple matches are there? Is this related to overload resolution rule or something else?

Thanks very much.

2

There are 2 best solutions below

2
On

The same overloading rules apply to extension methods as for all other methods. N is used because it is a better match. M may have an optional parameter, but the no parameter option is a better fit as the rules favour the option with the fewest parameters.

From Named and Optional Arguments (C# Programming Guide):

If two candidates are judged to be equally good, preference goes to a candidate that does not have optional parameters for which arguments were omitted in the call. This is a consequence of a general preference in overload resolution for candidates that have fewer parameters.

However, "closeness" comes into play with extension methods too, as described in Eric Lippert's blog:

The consequence of this is that if you restructure your code to:

namespace X
{
    public static class N
    {
        public static int Plus(this int i)
        {
            return i + 10;
        }
    }
}

namespace ConsoleApplication1
{
    public static class M
    {
        public static int Plus(this int i, int p = 6)
        {
            return i + p;
        }
    }

    internal class Program
    {
        private static void Main()
        {
            int i = 3.Plus();
            Console.WriteLine(i);
        }
    }
}

Then the number displayed is 9. In other words, the version with an optional parameter is chosen as it's in the same namespace and thus "closer".

0
On

This has nothing to do with extension methods specifically. At the tie breaking phase of the overload resolution algorithm, a method that matches the call without application of default arguments is preferred over a method that requires application of said default arguments to match the call.

As the C# specification puts it, at page 154:

[...] if all parameters of MP have a corresponding argument whereas default arguments need to be substituted for at least one optional parameter in MQ then MP is better than MQ.