为什么 C# 支持抽象成员的抽象覆盖?
Why does C# support abstract overrides of abstract members?
在浏览一些遗留代码时,我很惊讶地遇到了一个 对本身是抽象的成员的抽象覆盖。 基本上是这样的:
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#? 的重复,因为 class A
中的 DoStuff
方法不是虚拟的,而是抽象的。)
澄清问题:问题不是"why is an abstract override legal?"An existing question handles that. (See also my blog post的主题。)
相反,问题是"why is an abstract override legal when the overridden method is also abstract?"
这里有几个支持不给出错误的论据。
无害。
给个错误,编译器团队的某个人肯定已经想到了这个场景,认为值得花时间设计这个特性,验证它不会导致任何不良交互其他功能,编写详细的规范,实施它,测试它,编写文档,将错误消息翻译成两打语言,翻译文档,并永远维护该功能。证明这些成本合理的令人信服的好处是什么?我看到 none.
每当 C# 中的东西看起来很奇怪时问问自己 如果基础 class 的所有者不在我的团队中并且他们喜欢编辑它怎么办?
例如考虑您的场景的变体:
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();
}
classA 的作者意识到他们犯了一个错误,A 和 DoStuff 应该是抽象的。制作 class 摘要是一项重大更改,因为现在说 "new A()" 的任何人都错了,但他们验证了他们组织中的 none 客户团队已经创建了一个新的 A。同样,调用base.DoStuff
现在错了。但同样,还有 none.
所以他们将他们的代码更改为您的 class A 版本。class B 现在应该有一个编译时错误?为什么? B没问题。
C# 的许多功能看起来很奇怪,因为设计者认为脆弱的基础 class 是一个重要的场景。
- 最后,我们应该考虑覆盖方法的前提条件是什么。被覆盖的方法必须可以被覆盖代码访问,覆盖代码必须是派生类型,被覆盖的方法首先必须是虚方法。这些要求有明显的充分理由。引入另一项要求——重写要求重写和重写的方法中只有一个是抽象的——没有其背后的原则性原因。
在浏览一些遗留代码时,我很惊讶地遇到了一个 对本身是抽象的成员的抽象覆盖。 基本上是这样的:
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#? 的重复,因为 class A
中的 DoStuff
方法不是虚拟的,而是抽象的。)
澄清问题:问题不是"why is an abstract override legal?"An existing question handles that. (See also my blog post的主题。)
相反,问题是"why is an abstract override legal when the overridden method is also abstract?"
这里有几个支持不给出错误的论据。
无害。
给个错误,编译器团队的某个人肯定已经想到了这个场景,认为值得花时间设计这个特性,验证它不会导致任何不良交互其他功能,编写详细的规范,实施它,测试它,编写文档,将错误消息翻译成两打语言,翻译文档,并永远维护该功能。证明这些成本合理的令人信服的好处是什么?我看到 none.
每当 C# 中的东西看起来很奇怪时问问自己 如果基础 class 的所有者不在我的团队中并且他们喜欢编辑它怎么办?
例如考虑您的场景的变体:
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();
}
classA 的作者意识到他们犯了一个错误,A 和 DoStuff 应该是抽象的。制作 class 摘要是一项重大更改,因为现在说 "new A()" 的任何人都错了,但他们验证了他们组织中的 none 客户团队已经创建了一个新的 A。同样,调用base.DoStuff
现在错了。但同样,还有 none.
所以他们将他们的代码更改为您的 class A 版本。class B 现在应该有一个编译时错误?为什么? B没问题。
C# 的许多功能看起来很奇怪,因为设计者认为脆弱的基础 class 是一个重要的场景。
- 最后,我们应该考虑覆盖方法的前提条件是什么。被覆盖的方法必须可以被覆盖代码访问,覆盖代码必须是派生类型,被覆盖的方法首先必须是虚方法。这些要求有明显的充分理由。引入另一项要求——重写要求重写和重写的方法中只有一个是抽象的——没有其背后的原则性原因。