可选参数:如果存在重载覆盖,则反转优先级

时间:2015-04-01 13:39:52

标签: c# override overloading optional-parameters operator-precedence

我想知道以下行为:

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重载”写入控制台。

即使是resharper失败并陷入陷阱:

enter image description here

... 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"
    }
}

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

1 个答案:

答案 0 :(得分:4)

  

为什么具有精确签名的重载优先于具有可选参数的另一个重载,以防具有精确参数的重载覆盖基本实现?

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

编译器会查看"最深的"首先输入 - 即具有目标的编译时类型(在本例中为B)并尝试查找适用的函数成员忽略任何覆盖基类中声明的方法 >:

  

候选方法集被简化为仅包含来自大多数派生类型的方法:对于集合中的每个方法CF,其中C是声明方法F的类型,所有方法都在C的基本类型中声明从集合中移除。

  

上述解析规则的直观效果如下:要找到由方法调用调用的特定方法,请从方法调用指示的类型开始,然后继续继承链,直到至少一个适用的,可访问的,找到非重写方法声明。然后对在该类型中声明的适用的,可访问的,非重写方法集执行类型推断和重载解析,并调用由此选择的方法。如果未找到任何方法,请尝试将调用作为扩展方法调用进行处理。

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

我有article on overloading显示这种事情,不使用可选参数但使用不同的参数类型 - 请参阅"继承"部分。