可选参数:如果存在重载覆盖,则优先顺序相反

optional parameter: reversed precedence if override of overload exists

我想知道以下行为:

public class A {
    public virtual void Do() { Console.WriteLine("A"); }
}

public class B : A {
    public override void Do() { Console.WriteLine("B override"); }
    public void Do(int value = 0) { Console.WriteLine("B overload"); }
}

class Program {
    public static void Main() {
        new B().Do(); // ---> Console: "B overload"
    }
}

我希望具有确切签名的重载优先于另一个具有可选参数的重载:我希望在控制台中显示 "B override"。相反,程序将 "B overload" 写入控制台。

连resharper都失败掉进陷阱:

... Resharper说带有可选参数的重载被带有精确签名的重载隐藏了,但实际上恰恰相反

现在,如果您删除继承,那么它会按预期运行并且 resharper 警告是合法的:

public class B {
    public virtual void Do() { Console.WriteLine("B override"); }
    public void Do(int value = 0) { Console.WriteLine("B overload"); }
}

class Program {
    public static void Main() {
        new B().Do(); // ---> Console: "B override"
    }
}

所以问题是:解释这个观察的优先规则是什么?为什么具有精确签名的重载不优先于另一个具有可选参数的重载,以防具有精确参数的重载覆盖基本实现?

Why an overload with exact signature doesn't have precedence over another overload with optional parameters in case that the overload with exact parameters overrides a base implementation?

基本上这是遵循规范规则的编译器,尽管在这种情况下它们令人惊讶。 (第 7.6.5.1 节是 C# 5 规范的相关部分。)

编译器首先查看 "deepest" 类型 - 即具有目标编译时类型的类型(在本例中为 B)并尝试找到适用的函数成员 忽略任何重写基类中声明的方法 class:

The set of candidate methods is reduced to contain only methods from the most derived types: For each method C.F in the set, where C is the type in which the method F is declared, all methods declared in a base type of C are removed from the set.

和:

The intuitive effect of the resolution rules described above is as follows: To locate the particular method invoked by a method invocation, start with the type indicated by the method invocation and proceed up the inheritance chain until at least one applicable, accessible, non-override method declaration is found. Then perform type inference and overload resolution on the set of applicable, accessible, non-override methods declared in that type and invoke the method thus selected. If no method was found, try instead to process the invocation as an extension method invocation.

因此在您的情况下,编译器 考虑新引入的方法,发现它适用(使用默认参数值)并停止搜索。 (即它不查看在 base classes 中声明的方法)。那时,候选函数成员集只有一个条目,因此此时没有真正的重载决议要执行。

我有一个 article on overloading 显示了这种情况,它没有使用可选参数而是使用了不同的参数类型 - 请参阅 "Inheritance" 部分。