【发布时间】:2011-07-08 18:45:22
【问题描述】:
这里有一些代码供讨论
abstract class ClassA
{
public abstract void StartProcess();
}
class ClassB : ClassA
{
public override void StartProcess()
{
Console.WriteLine("ClassB: Render");
}
}
class ClassC : ClassA
{
public override void StartProcess()
{
base.StartProcess();//This is where the compiler complains
Console.WriteLine("ClassC: Render");
}
}
在每个人都从我的喉咙里跳下来之前,我只想说我完全知道为什么它没有。但在某些情况下,这样做是有意义的,并且可以避免将基类的方法声明为虚拟但实现为空。
来自 Delphi 背景,我们可以在 Delphi 中执行此操作,并将其用于我们的类设计。如果您错误地调用了基类的抽象方法(在运行时),则会出现“抽象错误”。
然后我希望(Delphi)编译器之前检查我! 现在我希望(C#)编译器能让我这样做! 这有多奇怪?
问题: 编译器/抖动不能简单地忽略这样的调用并发出警告而不是错误吗? 其他人是否看到/感觉到这种痛苦?
我需要的情况如下: ClassA 是库的一部分(无法控制此类) 生成 ClassC(有点像 ASP.NET 页面的编译方式或 Razor 视图的编译方式。
但是库的用户可以定义一个 ClassB,然后 ClassC 将从 ClassB 而不是 ClassA 下降(当它生成时)。类似于 ASP.NET 页面通常从 System.Web.UI.Page 下降的方式,但如果您已经定义了自己的“基本”页面和应用程序中的其他页面现在从您的基本页面下降,那么生成的类将从您的基本页面下降(又是 System.Web.UI.Page 的后代)。
我希望这部分很清楚。然后查看我提供的代码,我无法让 ClassC 的实例调用 ClassB 的实现,因为代码生成器不知道包含 base.StartProcess()。
编辑 似乎有些人不太明白我写的东西。因此,假设您正在编写生成从 ClassA 继承的 ClassC 的代码生成部分。好吧,由于该方法是 anstract (在 ClassA 中),因此您无法生成调用 StartProcess() 的代码行(因为编译器不允许这样做)。因此,如果有人定义了 ClassB,代码生成仍然不会调用 base.StartProcess()。这实际上是 ASP.NET MVC 视图中发生的情况。
理想情况下,我希望编译器忽略它。它忽略了许多事情,例如在 null 引用上调用 dispose。
我正在尝试进行讨论而不是被传教给...
EDIT2 假设我们有一个如上面代码所示的层次结构并且它有效。 我们现在拥有的机会是基类 ClassA 可以有一个实现(将来) StartProcess() 后代会调用它。今天这样做的唯一方法是定义没有主体的虚拟方法。但这对我来说有点恶心。
【问题讨论】:
-
“但在某些情况下,能够这样做是有意义的”我在等待......
-
不足为奇——这里的人们总是在展示他们有多聪明。我以为我们可以进行讨论而不是小便比赛……太糟糕了。如果您愿意,我正在编辑我的问题以包含其他信息。
-
@Jackie:在我看来这仍然没有意义。如果您的代码生成器明确声明 ClassC 从 ClassA 派生,那么我看不出 ClassB 将如何参与。我仍然很高兴 C# 编译器的行为方式如此。代码生成器需要知道 ClassB 以使 ClassC 派生自它,并且它可以轻松检查是否有要调用的实现。没问题。
-
@Jackie:您提供了一个代码生成器被破坏的示例。破坏语言并不是补偿损坏的代码生成器的正确方法 - 正确的更改是修复代码生成器或基类。如果代码生成器遇到方法调用错误的情况,那是否会成为 C# 变得不区分大小写的参数?不。如果你想要一个无操作方法,如果没有任何东西覆盖它,那正是空虚方法的意思。抽象方法强制重新实现,这根本不是一回事。
-
@Jackie:如果某些东西没有解决真正的问题,但它引入问题(我认为“当当前在编译时发现编码错误时,将其推迟到执行时") 作为引入一个问题,那么我认为没有太多讨论的必要。您声称您希望 C# 编译器能够像 Delphi 编译器那样工作 - 如果您没有突出的问题,您为什么希望这样做?如果您要提出更改,至少应该有一个具体的好示例说明它在哪里有用。我不认为“想象一个损坏的代码生成器”很重要。
标签: c# oop abstract-class