C#中的'abstract override'有什么用途?

59

只是出于好奇,我尝试覆盖抽象基类中的抽象方法,并将方法实现变为抽象。代码如下:

public abstract class FirstAbstract
{
    public abstract void SomeMethod();
}

public abstract class SecondAbstract : FirstAbstract
{
    public abstract override void SomeMethod();
    //?? what sense does this make? no implementaion would anyway force the derived classes to implement abstract method?
}

想知道为什么C#编译器允许使用'abstract override'这样的写法。这不是多余的吗?像这样做应该会在编译时出现错误。它有什么用处吗?

谢谢您的关注。


我已经使用过这个功能几次。它确实有用武之地。 - ChaosPandion
请参考以下链接:http://blogs.msdn.com/b/jmstall/archive/2005/08/07/abstract-override.aspx - S2S2
为什么仅仅是冗余的东西会导致编译时错误呢? - saus
2
@saus 因为有些冗余的东西非常愚蠢,它们会暗示一个错误或误解,因此适当的做法是产生一个错误或至少一个警告。在接口成员上使用 public 就是一个例子。 - Jon Hanna
我有一个使用案例并正在研究如何实现它,这让我找到了这个问题。你的问题回答了我的问题,谢谢! - palswim
7个回答

68

Microsoft Docs上有一个有用的例子,基本上您可以强制派生类为方法提供新的实现。

public class D
{
    public virtual void DoWork(int i)
    {
        // Original implementation.
    }
}

public abstract class E : D
{
    public abstract override void DoWork(int i);
}

public class F : E
{
    public override void DoWork(int i)
    {
        // New implementation.
    }
}
如果一个虚方法声明为抽象,那么对于继承自抽象类的任何类来说它仍然是虚的。继承抽象方法的类不能访问该方法的原始实现——在先前的例子中,F 类上的 DoWork 不能调用 D 类上的 DoWork。这样,抽象类可以强制派生类为虚方法提供新的方法实现。

2
如果我这样做会怎么样 F ff = new F(); D dd = ff as D; dd.DoWork(0);?那不是会调用 D 的实现吗?如果是这样的话,我能否在 FDoWork(int i) 中放置像 D dd = this as D; dd.DoWork(i); 这样的代码?那会调用 D 的实现吗? - Blueriver
4
与任何虚拟成员函数一样,它会调用实际对象的实现,因此在这种情况下,它将调用 F 的实现。 - Jon Hanna

57

我发现在确保派生类中正确实现 ToString() 方面非常有用。假设您有一个抽象基类,并且您真的希望所有派生类都定义有意义的 ToString() 实现,因为您正在积极使用它。您可以通过 abstract override 非常优雅地实现这一点:

public abstract class Base
{
    public abstract override string ToString();
}

这是对执行者的明确信号,即ToString()将以某种方式在基类中使用(例如向用户编写输出)。通常,他们不会考虑定义此重写。


1
点赞。这是一个非常好的例子,确实属于这个主题。同样的例子也在 Stack Overflow 的 另一个旧回答 中提供,只是为了比较。 - Jeppe Stig Nielsen

16

如果基类成员是virtual,那么这是有意义的,但是当基类成员是abstract时,编译器仍然允许它。除了防范基类成员可能有一天被更改为virtual之外,这是否是一个有效的模式? - binki

6
假设SecondAbstract处于三层类层次结构的中间,并且它想要实现其基类FirstAbstract的某些抽象方法,同时将一些其他方法X留给其子类ThirdAbstract来实现。
在这种情况下,SecondAbstract被迫用abstract修饰方法X,因为它不想提供实现;同时,它被迫用override修饰方法X,因为它不是定义一个新的方法X,而是想把实现X的责任移交给它的子类。因此,使用abstract override
一般来说,abstractoverride所模拟的概念是正交的。前者强制派生类实现方法,而后者认识到该方法与基类上指定的方法相同,而不是新的方法X。
因此:
  • 没有关键字:"简单"方法
  • abstract:派生类必须实现
  • override:实现在基类中定义的方法
  • abstract override:派生类必须实现在基类中定义的方法

1
但是,SecondAbstract并不需要包含方法X,因为SecondAbstract是一个抽象类。添加X并将其装饰为抽象覆盖等同于根本不包括X,这就是OP所说的冗余吧。 - saus
这是否意味着SecondAbstract对于基类方法X的实现不满意? - Eranga

0

这个设计模式被称为模板方法模式。

模板方法的维基百科页面

一个简单的非软件示例:有一堆军事单位:坦克、喷气式飞机、士兵、战舰等。它们都需要实现一些共同的方法,但它们的实现方式会非常不同:

  • 移动()
  • 攻击()
  • 撤退()
  • 休息()

等等...


0
这是因为在子类中,您不能使用与基类中相同名称的abstract方法。 override告诉编译器您正在覆盖基类的行为。
希望这就是您要找的内容。

0
如果您在SecondAbstract中没有将SomeMethod声明为abstract override,编译器会期望该类包含该方法的实现。使用abstract override可以清楚地表明实现应该在从SecondAbstract派生的类中而不是SecondAbstract本身中。

希望这可以帮助到您...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接