2009-07-14 101 views
3

可以说我有下面的C#类:.NET抽象覆盖怪癖

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 
{ 
} 

什么是“首选”写作方式?如果没有必要重写抽象方法或属性,为什么它被允许?

回答

5

您可能想要允许的一个原因:它显示意图。它解释说是的,你知道这个方法在基类中是抽象的。我知道,而我仍然希望它在这里抽象。这样,如果基类删除方法,则抽象类将无法编译,而不仅仅是具体类(甚至可能不在您的代码中)。

这就是说,这不是一个特别重要的原因......我通常会把它排除在外。

+0

我不知道我的理解是什么?增加一点编译失败的好处是什么?另外,如果您的基类增加了另一种抽象方法,并且您不重构衍生产品,您将不会持续获得此结果。 – LBushkin 2009-07-14 13:47:30

+0

@LBushkin:是的,你不会找到补充......但如果您不另外拥有*任何*(注意您的代码库中的任何地方可能没有具体的类),那么添加另一个失败点可能会非常有用。我不是说它会经常出现... – 2009-07-14 13:52:00

+1

赞赏继承树(描述性代码或*有意义的*评论)中的任何描述。继承使得基类和派生类的交互有点神秘 - 尤其是如果(a)基类不是一个简单的,精心设计的和集中的对象(b),如果维护者没有写出基类和派生类。继承是伟大的,但可以被极大地滥用,使神奇的笨拙代码 – STW 2009-07-14 13:56:19

0

您应该不需要重写b中的SomeMethod()。抽象类声明其中可能存在未定义/抽象方法。当你用另一个抽象类扩展一个抽象类时,它隐式地继承父类的任何抽象方法。

2

a look at this blog。有时候,结合这两个是非常有用的:

“好的语言设计通常会导致一些良好定义的简单 元,可以在直观和智能 方式一起结合 相反,不良的语言 设计通常会导致英寸许多臃肿 结构没有发挥好 在一起。

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

假设你有一个类层次结构: Ç的B派生,而B派生从 答:有一个抽象方法foo()和 粘粘()。这里有两种情况,其中 “抽象覆盖”会出现。 1) 假设B只想实现 Goo(),并让C实现Foo()。 B 可以将Foo()标记为“抽象覆盖”。 这清楚地表明B 可以识别Foo()在 基类A中声明,但它期望另一个 派生类来实现它。 2)让我们假设B想强制C改为 重新实现Foo(),而不是使用A的 定义Foo()。乙标记美孚()作为 二者覆盖(这意味着乙 识别符()中的 基类被声明)和抽象(这意味着派生C类提供一种 实施 乙力;不管是A 已经提供了一种实现)。 这是我最近的博客 这里的一个条目。在该示例中, A = TextReader,Foo = ReadLine,B = a 帮助程序类,C =某些类要实现ReadLine()而不是 Read()。现在TextReader已经有一个基于Read()的ReadLine() 的默认实现 ,但我们想要以其他方式去 。我们希望基于 的派生类实现 ReadLine()基于 实现Read()。因此,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"); 
    } 
} 

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

2

我通常不重新申报抽象方法时,我真的不打算提供一个实现 - 有以下几个原因:

  • 我不会改变你的代码的语义。
  • 如果基类发生变化,它会增加一件重构。
  • 它导致新的抽象方法的不一致性被添加到基类中,并且不会将它们添加到中间类中。
  • 在具有多个层次的课程层次结构中这样做是相当痛苦的。
  • 它增加了一点价值的声明凌乱你的代码。
2

附加到已经表示:

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

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