抽象类中的可选参数覆盖派生

时间:2013-12-08 10:44:32

标签: c# abstract-class optional-parameters

在抽象类中

public abstract class base
    {
        abstract public int Func(bool flag = true);
    }

我在派生版本中进行了更改:

public class derived : base
    {
        public override int Func(bool flag = false){}
    }

调试显示编译器使用true作为默认值。我没想到,为什么它会这样呢?

2 个答案:

答案 0 :(得分:3)

此行为在C#语言规范中的§7.5.1.1(对应参数,强调我的)中说明:

  

对于参数列表中的每个参数,必须有一个对应的参数   正在调用的函数成员或委托中的参数。该   以下使用的参数列表确定如下:

     
      
  • 对于在类中定义的虚方法和索引器,参数列表是   从最具体的声明或覆盖功能中挑选出来   成员,从接收器静态类型开始,然后搜索   通过其基类
  •   

在绑定(将方法与调用调用关联的过程)中,编译器使用上述规则找到一个参数列表,然后是一组符合该参数列表的候选方法。其中最好的一个被挑选并绑定到调用 拿这个代码:

BaseClass b = new DerivedClass( );
b.Func( );

在绑定期间,使用的参数列表是BaseClass.Func中声明的参数列表(因为这是b的静态类型),候选方法集是BaseClass.Func和{{1} (据说它们是适用的,因为两个参数列表都对应于所选的一个)。然后DerivedClass.Func被认为是最佳候选者,因此可以使用DerivedClass.Func 的参数列表绑定到的调用,因此使用BaseClass.Func

您可以在§7.5.3(重载分辨率)中找到更多详细信息。最后,如果您想知道,抽象方法被认为是虚拟的,如§10.6.6(抽象方法)中所述:

  

抽象方法声明引入了一个新的虚方法,但没有提供   该方法的实现。

答案 1 :(得分:1)

我创建了一个模仿你情况的sample。简而言之:使用哪个默认值取决于您是通过基类类型的变量还是派生类来访问实例。因此编译器会根据变量的类型检测可选参数的默认值。这是有道理的,因为您可以在变量(多态)中存储派生类的任何实例。在编译时可能甚至不清楚if if instance的类型(例如,如果你将系统配置为使用特定类型)。所有编译器都知道变量的类型,并且以类型安全的方式放入其中的任何实例都提供相同的接口。

using System;

public abstract class MyBase
{
    public abstract bool GetValue(bool value = true);
}

public class MyDerived : MyBase
{
    public override bool GetValue(bool value = false)
    {
        return value;
    }
}

public class Test
{
    public static void Main()
    {
        var derived = new MyDerived();
        Console.WriteLine("Value = {0}", derived.GetValue());
        MyBase myBase = derived;
        Console.WriteLine("Value = {0}", myBase.GetValue());
    }
}

我假设您在基类类型的变量上调用该方法,这将解释行为 基本上,如果您不覆盖该方法但影响它,这类似于行为。在几乎所有情况下,您都希望避免这种情况,因为代码不会以您期望的方式运行的风险相对较高。
因此我建议摆脱可选参数并使它们成为必需参数(并且可能在没有参数的情况下创建一个过载)。必须输入较少并且以后能够更改默认值不值得冒着代码意外行为的风险。这种行为现在对你来说可能是透明的,但我怀疑它会在几个月之后或者你的同事必须维护代码。