在 C# 中具有默认值的参数和具有相似签名的 void - 编译器如何知道要调用哪一个?

Parameter with default value and void with similar signature in C# - how does the compiler know which one to invoke?

假设我有以下两种简单的方法:

class Question
{
    public void MyMethod()
    {
        Console.WriteLine("no params here");
    }

    public void MyMethod(object o = null)
    {
        Console.WriteLine("an object here");
    }
}

我这样调用一个:

new Question().MyMethod();

它导致调用无参数方法,写入 "no params here"。

我知道我仍然可以打电话给对方,例如喜欢

new Question().MyMethod(null);

但我的问题是,为什么编译器不警告我可能存在的歧义或强制我说清楚?它如何决定调用什么?只是参数少的那个?

And how does it decide what to call?

它应用 MS specification or ECMA standard 中的规则(由您选择)。重载 真的 复杂 - 特别是当你有类型推断、继承、可选参数、无类型参数(例如 nulldefault、方法组或lambda 表达式)涉及。

在这种情况下,相对简单。这两种方法都适用,并且在参数转换方面"better"都不比另一个,因为没有任何参数。然后有平局规则 - 在这种情况下重要的是(ECMA 版本):

If neither function member was found to be better, and 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. Otherwise, no function member is better.

换句话说,它不是模棱两可的,因为一种方法没有可选参数而没有相应的参数,而另一种方法有。

请注意,需要自动替换的不是 "fewer" 可选参数的问题 - 它是 "were there any or not"。

例如,请考虑:

class Question
{
    public void MyMethod(int x = 1) {}
    public void MyMethod(int x = 1, int y = 2) {}
}

class Test
{
    static void Main()
    {
        // Ambiguous
        new Question().MyMethod();
        // Unambiguous
        new Question().MyMethod(0);
    }        
}

第一次调用(无参数)不明确,因为两种适用的方法都有可选参数,但没有相应的参数。

第二次调用(一个参数)选择带有单个参数的方法,因为即使一个可选参数,它也有相应的参数——而带有两个参数的方法parameters 仍然有一个没有对应参数的可选参数。

根据 MSDN 过载解决方案 部分:

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.

一个具有完全匹配的参数计数,一个具有通过在调用站点插入默认值合并匹配的参数计数。编译器的“最佳”选择显然是前者。

如果不是这样,那么您将如何调用无参数方法?你不能,所以添加一个带有所有可选参数的重载会破坏调用者代码:最初调用无参数方法的代码现在会调用不同的方法。

至于为什么不是编译器警告,我不能告诉你原因。它可能应该是重载声明站点的警告,因为这是 API 作者的“错误”。这不是呼叫者的错,因此在呼叫站点发出警告毫无意义,尤其是当呼叫者一方没有可用的“修复”时。