2009-07-14 96 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(); 
}