好像是在.NET Framework重写该方法时,可选参数存在问题.下面代码的输出是:

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

类中的方法可以执行以下一到两项操作:

  1. 它定义了供其他代码调用的接口.
  2. 它定义了调用时要执行的实现.

它可能不能同时做这两件事,因为抽象方法只做前一件事.

BBB内,调用MyMethod()AAA中调用方法defined.

因为BBB中有一个覆盖,所以调用该方法会导致调用BBB中的实现.

现在,AAA中的定义告知调用代码两件事(好吧,还有其他几件事在这里无关紧要).

  1. 签名是void MyMethod(string).
  2. (对于那些支持它的语言)单个参数的默认值是"aaa",因此,当编译表单MyMethod()的代码时,如果找不到与MyMethod()匹配的方法,您可以用调用`MyMethod("aaa")替换它.

这就是BBB中的调用所做的:编译器看到了对MyMethod()的调用,没有找到方法MyMethod(),但找到了方法MyMethod(string).它还看到,在定义它的地方有一个默认值"aaa",所以在编译时它将其更改为对MyMethod("aaa")的调用.

BBB范围内,AAA被认为是定义AAA方法的地方,即使在BBB中被重写,也会被过度使用.

在运行时,用参数"aaa"调用MyMethod(string).因为有一个被重写的表单,即被调用的表单,但它不是用"bbb"调用的,因为该值与运行时实现无关,而是与编译时定义有关.

添加this.个参数将更改要判断的定义,从而更改调用中使用的参数.

编辑:为什么这在我看来更直观.

就我个人而言,既然我说的是直觉,那么它只能是个人的,我觉得这更直观,原因如下:

如果我是编码BBB,那么无论是调用还是重写MyMethod(string),我都会认为这是"做AAA件事"——它是BBB,而"做AAA件事",但它做AAA件事都是一样的.因此,无论是调用还是重写,我都会意识到,定义MyMethod(string)的是AAA.

如果我调用使用BBB的代码,我会想到"使用BBB个东西".我可能不太清楚最初是在AAA中定义的,我可能会认为这只是一个实现细节(如果我不在附近使用AAA接口的话).

编译器的行为符合我的直觉,这就是为什么在我第一次阅读这个问题时,Mono似乎有一个bug.考虑到这一点,我看不出其中一个比另一个更好地实现特定的行为.

尽管如此,在保持个人水平的同时,我永远不会对抽象、虚拟或重写的方法使用可选参数,如果重写了其他人的方法,我会匹配他们的方法.

.net相关问答推荐

当数据大量分布在微服务中时,我应该如何设计后端?

如何使用 awslocal 通过 localstack 中的 cloudwatch events/eventbridge 触发 lambda

信号量的多线程问题

问:在 Blazor WASM 应用程序中存储 api 密钥的最佳方式是什么?

为什么 .net 对字符串使用 UTF16 编码,但默认使用 UTF-8 来保存文件?

如何从标头中检索基本身份验证凭据?

.NET 的 Visual Studio 调试器提示和技巧

在 C# DllImport 中使用 32 位或 64 位 dll

实例化具有运行时确定类型的对象

如何在 C# 中打开 Excel 文件?

返回 IQueryable 或不返回 IQueryable

修剪数组中的所有字符串

从 Windows 窗体打开 URL

我不了解应用程序域

自定义属性的构造函数何时运行?

有没有办法从方法返回匿名类型?

String.Replace() 与 StringBuilder.Replace()

SqlCommand.CommandTimeout 和 SqlConnection.ConnectionTimeout 有什么区别?

如何为我的 C# 应用程序创建产品密钥?

Roslyn 编译代码失败