2009-12-04 61 views
3

假設類A從繼承自類C的類B繼承。現在假設在A中定義了一個虛擬方法void f(),它在B和C中均被重寫。從任何方法調用Bf()在A中可以通過簡單地使用base.f()來完成。那麼從A中的方法調用C.f()怎麼樣?C#如何調用基地的基礎方法?

+4

可能的重複:http://stackoverflow.com/questions/1006530/c-how-to-call-a-second-level-base-class-method-like-base-base-gethashcode – itowlson 2009-12-04 00:32:56

+0

我假設你的意思是從C中的方法調用Af()? – 2009-12-04 00:34:38

+0

我真的只是猜測,但你不能把'this'給C嗎? ((C)這一點).F(); – 2009-12-04 00:46:17

回答

10

通常,通過覆蓋一個類,您接受它提供了所需的接口和一些行爲。 A不應該知道它是超類,除非它的超類以某種方式明確暴露。這實際上是可取的,因爲當你繼承B時,你不需要知道C是如何實現的。你甚至不應該知道C涉及到了。如果b的f()調用base.f(),a的base.f()只需調用它自己的base.f(),就完成了。如果沒有,自己做的唯一方法就是通過基於反射的侵入式方法。如果你發現自己需要這樣做,那麼你的設計可能會出錯(違反德米特法則)。

+0

謝謝,這不是我自己的設計。在這種情況下,B類和C類是Telerik組件。 B類提供了我所需要的大部分功能,但爲了實現我需要用C調用方法的一些功能。 – sisis 2010-04-02 18:17:42

0

試試這個:

C c = this; 
c.f(); 

這版畫 「C」:

public static void Main() 
{ 
A o = new A(); 
Console.WriteLine(o.f()); 
} 

class C 
{ 
public virtual string f() 
{ 
    return "C"; 
} 
} 

class B : C 
{ 
public virtual string f() 
{ 
    return "B"; 
} 
} 

class A : B 
{ 
public virtual string f() 
{ 
    C c = this; 
    return c.f(); 
} 
} 
+0

這似乎並沒有編譯(當我嘗試它)。你是否想過C++,它具有類似的語法來調用繼承鏈上的方法? – itowlson 2009-12-04 00:36:13

+0

這不是編譯,也不是理論上的工作,你不能調用那樣的方法,除非它們是靜態的,在這種情況下,它們不能是虛擬的。 – 2009-12-04 00:40:10

+0

對不起,我確實有一個C++判斷失誤。用解決方法進行編輯。 – Jason 2009-12-04 03:04:05

1

這可以通過反射來完成。獲取當前類的Type,使用它獲取父類型,然後獲取父類型的父類型。

它不直接支持語言的原因是它打破了繼承的抽象模型。它與傳統的面向對象設計不兼容。

3

您可以通過反射或與IL代碼生成。除此之外,你不能,你真的不應該,這聽起來不像是好設計。

當您重寫OOP中的方法時,基本上說「對於此類型,此方法將替換舊方法」,並且可以根據需要(通常是此方法)調用替換的重寫)方法。

但是,您不能直接跳過關卡,除非您使用反射或IL欺騙,並且有一個很好的理由。如果中間類應該允許您跳過此方法調用,則應該爲其添加一個特殊的方法,以供您使用。這很難做到的原因是你通常不應該這樣做,你應該總是進入下一個階段,這樣才能保持控制。

1

我假設你的意思是從C中的方法調用A.f()。

簡短的回答:你不能

不過,如果你有超過B控制,你可以添加一個方法給B打電話給其基礎明確:

protected void BaseF() 
{ 
    base.f(); 
} 

然後調用該方法從C

0

從C函數中,你可以調用base.f(),,這是你應該做的。如果B.f()(也就是你實際調用的內容)選擇調用base.f(),那麼它可以達到你想要的,但是完全取決於B的實現情況。

您可以嘗試鑄件C爲A和調用F(),像這樣:

public class C : B { 
    public override f() { 
     ((A) this).f(); 
    } 
} 

,但這樣做的問題是,C不知道其中f()聲明 - 它只知道在B中有一個可以被覆蓋的實現,C不知道A存在。上面的例子實際上是一段糟糕的代碼,如果A沒有實現f(),將會產生編譯時錯誤。

0

使用new而不是override是一種方式(該功能不需要是虛擬的即可使用new)。

雖然這可能會給你一些其他問題。如果你將MyClass上傳到MyBaseClass任何地方,它將使用MyBaseClass版本的功能。

private void Form1_Load(object sender, EventArgs e) 
{ 

    var mc = new MyClass(); 

    mc.Foo(); 
    ((MyBaseClass) mc).Foo(); 
} 


public class MyBaseClass 
{   
    public virtual void Foo() 
    { 
     Console.WriteLine("Calling from MyBaseClass"); 
    } 
} 

public class MyClass : MyBaseClass 
{ 

    new public void Foo() 
    { 
     Console.WriteLine("Calling from MyClass"); 
    } 
} 

你得到的輸出是:

Calling from MyClass 
Calling from MyBaseClass 
0

正如前面的評論,虛擬永遠不能以這種方式被覆蓋,並且您必須使用「新」,而不是「覆蓋」。

下面是使用你的類名的例子:

這不是一個很好的做法,因爲它變得非常混亂,打破了很多預期的傳承行爲,以及「新」的關鍵字是爲了迫使新的接口項目放到不打算被覆蓋的類上。

乾杯, 傑森

class Program 
{ 
    static void Main(string[] args) 
    { 
     C c = new C(); 
     A a = new A(); 
     a.DoThis(); 
     Console.ReadKey(); 
    } 
} 

public class C 
{ 
    public virtual void DoThis() { 
     Console.WriteLine("In C"); } 
} 

public class B : C 
{ 
    public new void DoThis() 
    { 
     Console.WriteLine("In B"); 
    } 
} 

public class A : B 
{ 
    public new void DoThis() 
    { 
     Console.WriteLine("In A.."); 
     ((C) this).DoThis(); 
    } 
} 
0

這似乎是一個設計問題。

一對夫婦的選擇,您都:

  1. 拿大頭A.DoThis()的,並將其移動到另一種方法(保護?)叫適當的東西(找時間做()?)。現在,你可以直接調用它。
  2. 拆分你的對象,並考慮使用組合而不是繼承來重用行爲。