.net抽象覆盖怪癖

时间:2009-07-14 13:38:44

标签: c# .net

假设我有以下c#类:

abstract class a
{
    protected abstract void SomeMethod();
}

abstract class b : a
{
    protected abstract override void SomeMethod();
}

class c : b
{
    protected override void SomeMethod()
    {

    }
}

在b中覆盖方法实际上是否有任何意义,因为它可以很容易地写成:

abstract class b : a
{
}

写作b的“首选”方式是什么?如果没有重写覆盖抽象方法或属性的原因,为什么允许它?

5 个答案:

答案 0 :(得分:5)

您可能想要允许它的一个原因:它显示意图。它解释了是的,你知道这个方法在基类中是抽象的。我知道,我仍然希望它在这里是抽象的。

这样,如果基类删除了该方法,那么您的抽象类将无法编译,而不仅仅是具体的类(甚至可能不在您的代码中)。

那就是说,这不是一个特别重要的原因......我通常会把它抛弃。

答案 1 :(得分:3)

除了已经说过的话:

override也可用于声明属性,这些属性未在基类中定义。如果仍然没有实现,它将是一个抽象覆盖。

abstract class b : a
{
  [SomeAttribute]  
  protected abstract override void SomeMethod();
}

答案 2 :(得分:2)

拥有a look at this blog。有时将两者结合起来很有用:

  

“通常会产生良好的语言设计   在几个明确定义的简单   可以组合的原语   一起直观而聪明   方法。相比之下,语言不佳   设计通常导致许多臃肿   构造不好的   在一起。

     

“抽象”和“覆盖”关键字   在C#中就是一个很好的例子。   它们都有简单的定义,但是   他们可以结合起来表达更多   复杂的概念也是如此。

     

假设你有一个类层次结构:   C来自B,而B来自   A. A有一个抽象方法Foo()和   粘粘()。这里有两个场景   “抽象覆盖”会出现。 1)   假设B只想实现   Goo(),让C实现Foo()。乙   可以将Foo()标记为“抽象覆盖”。   这清楚地表明了B   识别Foo()在。中声明   基类A,但它期待另一个   派生类来实现它。

     

2)让我们说B想强迫一个C.   重新实现Foo()而不是使用A的   Foo()的定义。 B将Foo()标记为   都覆盖(这意味着B   识别Foo()在。中声明   基类)和抽象(意思是   B强制派生C类提供   实施;不管那个A.   已经提供了一个实现)。   这出现在我最近的一篇博客中   条目在这里。在那个例子中,   A = TextReader,Foo = ReadLine,B = a   辅助类,C =想要的某个类   实现ReadLine()而不是   读()。现在TextReader已经有了   ReadLine()的默认实现   基于Read(),但我们想要去   其他方式。我们想要一个   基于a的Read()的实现   派生类的实现   的ReadLine()。因此B提供了一个   消耗的Read()的实现   ReadLine(),然后标记ReadLine()   作为“抽象覆盖”来强制C来   重新定义ReadLine()而不是拾取   从TextReader中获取一个。

     

总之,“抽象覆盖”是   很酷,不是因为它还有一个   语言功能来表达一些   复杂的角落案例;这很酷,因为   它不再是一种语言功能。   整洁的部分是你不是真的   需要考虑这一点。您   只使用个别的基本概念   自然而然,复杂的东西   自动结合在一起。“

这是方案1的示例代码:

public abstract class A
{
    public abstract void Foo();
    public abstract void Goo();
}

public abstract class B : A
{

    public abstract override void Foo();

    public override void Goo()
    {
        Console.WriteLine("Only wanted to implement goo");
    }
}

public class C : B
{

    public override void Foo()
    {
        Console.WriteLine("Only wanted to implement foo");
    }
}

我的方案2示例代码:

public abstract class A
{
    public virtual void Foo()
    {
        Console.WriteLine("A's Foo");
    }
    public abstract void Goo();
}

public abstract class B : A
{

    public abstract override void Foo();

    public override void Goo()
    {
        Console.WriteLine("Only wanted to implement goo");
    }
}

public class C : B
{

    public override void Foo()
    {
        Console.WriteLine("Forced to implement foo");
    }
}

在你的问题中,代码没有用,但这并不意味着抽象和覆盖组合没用。

答案 3 :(得分:2)

当我实际上并不打算提供实现时,我通常不会重新声明抽象方法 - 原因如下:

  • 我不会更改代码的语义。
  • 如果基类发生变化,它还会为重构添加一个东西。
  • 这会导致新的抽象方法不一致,并且不会将它们添加到基类中。
  • 在具有多个级别的类层次结构中这样做非常痛苦。
  • 它使您的代码混乱,声明增加的价值很小。

答案 4 :(得分:0)

您不需要在b中覆盖SomeMethod()。抽象类声明可以有未定义/抽象方法。当您使用另一个抽象类扩展一个抽象类时,它会隐式地从父级继承任何抽象方法。