似乎在.NET Framework中,重写该方法时,可选参数存在问题。以下代码的输出是:“ bbb”“ aaa”。但是我期望的输出是:“ bbb”“ bbb”。是否有解决方案?我知道可以通过方法重载来解决,但想知道这样做的原因。该代码在Mono中也可以正常工作。
class Program { class AAA { public virtual void MyMethod(string s = "aaa") { Console.WriteLine(s); } public virtual void MyMethod2() { MyMethod(); } } class BBB : AAA { public override void MyMethod(string s = "bbb") { base.MyMethod(s); } public override void MyMethod2() { MyMethod(); } } static void Main(string[] args) { BBB asd = new BBB(); asd.MyMethod(); asd.MyMethod2(); } }
这里需要注意的一件事是,每次都会调用覆盖的版本。将替代更改为:
public override void MyMethod(string s = "bbb") { Console.Write("derived: "); base.MyMethod(s); }
输出为:
derived: bbb derived: aaa
类中的方法可以执行以下一项或多项操作:
它可能不会两者都做,因为抽象方法只会做前者。
在BBB调用MyMethod()调用方法 定义 在AAA。
BBB
MyMethod()
AAA
由于中存在覆盖BBB,因此调用该方法将导致实现BBB被调用。
现在,中的定义AAA将两件事告知调用代码(嗯,还有一些无关紧要的地方)。
void MyMethod(string)
"aaa"
因此,这就是调用的BBB作用:编译器看到对的调用MyMethod(),未找到方法,MyMethod()但确实找到了方法MyMethod(string)。它还可以看到在定义它的地方有一个默认值“ aaa”,因此在编译时它将其更改为对的调用MyMethod("aaa")。
MyMethod(string)
MyMethod("aaa")
从内部BBB,即使在中被覆盖,也AAA被认为AAA是定义方法的地方BBB,以便 可以 覆盖它们。
在运行时,MyMethod(string)使用参数“ aaa”调用。因为存在一个覆盖的形式,所以该形式被调用,但是不使用“ bbb”来调用它,因为该值与运行时实现无关,而与编译时定义无关。
添加this.更改将检查哪个定义,从而更改调用中使用的参数。
this.
编辑:为什么这对我来说似乎更直观。
就个人而言,由于我所说的是直观的东西,因此只能是个人的,我发现它更直观,原因如下:
如果我正在编码,BBB那么无论是调用还是覆盖MyMethod(string),我都认为这是“正在做的AAA事情”,这是BBB在“正在做的AAA事情” 上做的事情,但实际上AAA都是在做事情。因此,无论是调用还是覆盖,我都将意识到它就是AAA定义的事实MyMethod(string)。
如果我要调用使用过的代码BBB,我会想到“使用BBB东西”。我可能不太了解最初是在中定义的AAA,因此我可能会认为这只是实现细节(如果我也没有使用AAA附近的接口)。
编译器的行为符合我的直觉,这就是为什么当初读这个问题时,我觉得Mono有一个错误。经考虑,我看不到任何一个如何比另一个更好地实现指定的行为。
尽管如此,尽管如此,在保持个人水平的同时,我绝不会将可选参数与抽象,虚拟或重写方法一起使用,并且如果要覆盖其他人使用的参数,我会匹配它们。