Неоднозначный вызов соответствует путанице


Следующий код выдает "неоднозначное совпадение вызова"во время компиляции:

class ABC{}
class DEF{}
class Program
{
    static void Main(string[] args)
    {
        Debug.WriteLine(func(null));
    }
    static string func(ABC abc)
    {
        return "";
    }
    static string func(DEF def)
    {
        return "";
    }
}

Но следующий код компилируется и работает нормально:

static void Main(string[] args)
{
    Debug.WriteLine(func(null));
}
static string func(int? abc)
{
    return "function a";
}
static string func(float? def)
{
    return "function b";
}

Вывод

function a

Как C# узнает, какую функцию выбрать во втором примере?

1 5

1 ответ:

Когда компилятор выполняет разрешение перегрузки для вызова функции, подобной этой, он выбирает лучший функциональный членсреди кандидатов, если таковой существует. Определение лучшего функционального члена включает этот отрывок в §7.5.3.2 спецификации языка C#:

7.5.3.2 лучший функциональный член

[...]

Задан список аргументов A с набором выражений аргументов { E1, E2, ..., ЕП } и двумя действующими членами функции МП и MQ с параметром типы { P1, P2, ..., PN } и { Q1, Q2, ..., QN }, MP определяется как лучший функциональный член, чем MQ, если

  • для каждого аргумента неявное преобразование из EX в QX является не лучше, чем неявное преобразование из EX в PX, и
  • по крайней мере для одного аргумента преобразование из EX в PX является лучше, чем преобразование из EX в QX.

[...]

В этом случае MP является первым методом (P1 будучи int?) и MQ является вторым методом (Q1 будучи float?). Таким образом, поведение легко объяснимо, если мы можем доказать, что преобразование из null в int? является лучше, чем преобразование в float?.

Это определяется правилами в §7.5.3.5:

7.5.3.5 лучшая цель преобразования

Учитывая два различных типа T1 и T2, T1 является лучшей целью преобразования чем T2, если выполняется хотя бы одно из следующих условий:

  • неявное преобразование из T1 в T2 существует, и никакого неявного преобразования из T2 в T1 не существует

Поскольку неявное преобразование из int в float существует, но одно из float в int не имеет (ссылки), int является ли лучшей целью преобразования при выборе между двумя типами.

В вашем примере мы имеем дело с обнуляемыми версиями этих типов, но та же логика применима из-за

[14]}6.1.4 неявное обнуление преобразования

Предопределенные неявные преобразования, которые работают с ненулевым значением типы также могут использоваться с формами, допускающими обнуление этих типов.