【问题标题】:Why does C# support abstract overrides of abstract members?为什么 C# 支持抽象成员的抽象覆盖?
【发布时间】:2018-02-22 04:26:41
【问题描述】:

在浏览一些遗留代码时,我惊讶地发现抽象覆盖本身就是抽象的成员。基本上是这样的:

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("!");    
}

虚拟或抽象成员之间的区别不是总是可供编译器使用吗?为什么 C# 支持这个?

(这个问题不是What is the use of 'abstract override' in C#? 的重复,因为A 类中的DoStuff-方法也不是虚拟的,而是抽象的。)

【问题讨论】:

  • 在你的例子中 DoStuff method 在类 A 中是抽象的,所以抽象覆盖在 B 类中没有意义,也没有必要,当 DoStuff 在类 @987654330 中时它是有意义的@ 是虚拟的,因此您可以将其设为“抽象覆盖”以强制类 C 实现它
  • 我知道抽象覆盖没有意义。我要问的是为什么 C# 首先支持它。 (我想知道它是否有我不知道的附加值)
  • 这也让我感到惊讶。见ericlippert.com/2011/02/07/strange-but-legal
  • 我不认为这是一个骗局。问题不是为什么抽象覆盖是合法的,而是为什么覆盖抽象的抽象是合法的。

标签: c# abstract


【解决方案1】:

澄清问题:问题不是“为什么抽象覆盖合法?” An existing question 处理。 (有关该主题,另请参阅 my blog post。)

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

这里有几个支持不给出错误的论据。

  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();
}

A 类的作者意识到他们犯了一个错误,A 和 DoStuff 应该是抽象的。将类抽象化是一项重大更改,因为现在说“new A()”的任何人都是错误的,但他们会验证其组织中的客户团队都没有创建新的 A。同样,调用 base.DoStuff 现在是错误的。但同样,没有。

所以他们将代码更改为您的 A 类版本。B 类现在应该有编译时错误吗?为什么? B没问题。

C# 的许多看起来很奇怪的特性都存在,因为设计者认为脆弱的基类是一个重要的场景。

  1. 最后,我们应该考虑覆盖方法的先决条件。被覆盖的方法必须可由覆盖代码访问,覆盖代码必须是派生类型,并且被覆盖的方法首先必须是虚拟方法。这些要求有明显的充分理由。引入另一个要求 - 覆盖要求不超过一个覆盖和覆盖的方法是抽象的 - 并没有其背后的原则原因。

【讨论】:

  • 哇,我没想到 Lippert 先生本人会回复我。特别是你的第三个论点对我来说很有意义。感谢您花时间为我提供如此广泛的答案!
  • @RobWijkstra:不客气;感谢您提出有趣的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-03-03
  • 1970-01-01
  • 2013-09-12
  • 2022-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多