为什么C#支持抽象成员的抽象覆盖?

Rob*_*tra 15 c# abstract

浏览一些遗留代码时,我很惊讶地遇到了一个抽象覆盖的成员,它本身就是抽象的.基本上,这样的事情:

public abstract class A
{
    public abstract void DoStuff();    
}

public abstract class B : A
{
    public override abstract void DoStuff();  // <--- Why is this supported?
}

public abstract class C : B
{
    public override void DoStuff() => Console.WriteLine("!");    
}
Run Code Online (Sandbox Code Playgroud)

编译器是否始终可以使用虚拟或抽象成员之间的区别?为什么C#支持这个?

(这个问题与C#中'抽象覆盖'的用法什么不重复 因为DoStuff类中的-method A不是虚拟的,而是抽象的.)

Eri*_*ert 17

澄清问题:问题不是"为什么抽象覆盖合法?" 现有问题处理这个问题.(另请参阅关于此主题的博客文章.)

相反,问题是"当被覆盖的方法也是抽象的时,为什么抽象覆盖是合法的?"

有几个论据赞成不在这里给出错误.

  1. 这是无害的.

  2. 为了给出错误,编译器团队中的某个人必须考虑到这种情况并认为值得花时间设计该功能,验证它不会导致与其他功能的任何不良交互,编写详细的规范,实现它,测试它,编写文档,将错误消息翻译成二十几种语言,翻译文档,并永久维护该功能.证明这些成本的合理性是什么?我没有看到.

  3. 每当C#中的某些东西看起来很奇怪时,问问自己,如果基类是由不在我团队中的人所拥有并且他们喜欢编辑它的话?

例如,考虑您的方案的变体:

public abstract class Z 
{
  public abstract void DoStuff();
}

public class A : Z
{
    public override void DoStuff() 
    { 
      throw new NotImplementedException(); 
    }
}

public abstract class B : A
{
    public override abstract void DoStuff();
}
Run Code Online (Sandbox Code Playgroud)

A类的作者意识到他们犯了一个错误,A和DoStuff应该是抽象的.制作一个抽象类是一个突破性的变化,因为任何说"新A()"的人现在都错了,但他们验证他们的组织中没有一个客户团队创建了新的A.同样,调用base.DoStuff现在是错误的.但同样,没有.

因此,他们将代码更改为您的A 版本 .B类现在是否有编译时错误?为什么?B.没有错.

C#的许多功能看似奇怪,因为设计师认为脆弱的基类是一个重要的场景.

  1. 最后,我们应该考虑覆盖方法的前提条件.重写的方法必须可以通过覆盖代码访问,覆盖的代码必须是派生类型,并且重写的方法必须首先是虚方法.这些要求有明显的理由.引入另一个要求 - 覆盖要求覆盖和覆盖的方法中只有一个是抽象的 - 没有一个原则性的原因.