2017-04-24 153 views
-5

關於繼承,隱藏和重載的一個小問題。繼承,隱藏和重載

我有以下類:

public class A 
{ 
    public BasicProject project { get; set; } 
    public int a {get; set;} 
} 

public class B : A 
{ 
    public AdvancedProject project { get; set; } 
    public int b {get; set;} 
} 

public class C : A 
{ 
    public new AdvancedProject project { get; set; } 
    public int c {get; set;} 
} 

public class BasicProject 
{ 
    public int p1 {get; set;} 
    public int p2 {get; set;} 
} 

public class AdvancedProject : BasicProject 
{ 
    public int p3 {get; set;} 
    public int p4 {get; set;} 
} 

另外我有一些功能

A show(A x) 
{ 
    x.project.p1; 
    x.project.p2; 
    x.project.p3; 
    x.project.p4; 
} 

的問題是,當我通過起作用B型(或C)的一個目的,所述x.project指的是BasicProject類型,而不是AdvancedProject

+1

這是因爲該方法只知道'A'。如果你想訪問'B'屬性,你應該將其轉換爲'B'或使用泛型。 –

+0

這是因爲在'A'中'project'不是虛擬的,如果是'你必須'在'B'中覆蓋它,那麼它仍然必須具有相同的類型。 – juharr

+0

@juharr添加虛擬/覆蓋導致編譯錯誤「類型必須是'BasicProject'以匹配被覆蓋的」成員'A.project' – Ilan

回答

1

一種方法來處理它是這樣的:

A show(A x) 
{ 
    x.project.p1; 
    x.project.p2; 
    var y = x as B; 
    if(y != null) 
     y.project.p3; 
     y.project.p4; 
    } 
    var z = x as C; 
    if(z != null) 
     z.project.p3; 
     z.project.p4; 
    } 
} 

然而,這是繼承的濫用,而且我不會推薦它。

0

您所描述的行爲是通過設計來實現的,您不應該試圖對付它。

如果您將類型爲A的參數傳遞給某個方法,則所有該方法知道的是它的類型爲A。實際的引用可能是一個繼承自A的類的實例,但該方法不知道。

您幾乎總是希望避免投射某些東西來查看底層類型是什麼。這打破了繼承和強打字的目的。我們可以使我們所有的方法參數object,然後嘗試鑄造它們,看看它們是什麼類型。如果你發現自己必須這樣做,這是一個跡象表明出現了問題,在繼續之前回溯並解決問題是一件好事。

目前還不清楚是什麼Show是,但也許這應該是BasicProjectAdvancedProject可以覆蓋的方法。或者,也許這兩個類有一個產生一些輸出的方法(比如值的集合),並且Show調用該方法並對這些值執行某些操作。

那樣Show不必知道它是否與BasicProjectAdvancedProject對話。它只是調用這個類的一個方法,並且結果會根據它與哪個類型交談而有所不同。這是多態。你不知道你是否真的在處理一個繼承的類,而與你知道的類型(BasicProject)進行交互。你只想「知道」傳遞給方法的類型。

例如:

public class BasicProject 
{ 
    public int p1 { get; set; } 
    public int p2 { get; set; } 
    public virtual IEnumerable<int> GetValues() 
    { 
     return new [] {p1, p2}; 
    } 
} 

public class AdvancedProject : BasicProject 
{ 
    public int p3 { get; set; } 
    public int p4 { get; set; } 

    public override IEnumerable<int> GetValues() 
    { 
     var values = new List<int>(base.GetValues()); 
     values.Add(p3); 
     values.Add(p4); 
     return values; 
    } 
} 

public class AdvancedProject : BasicProject 
{ 
    public int p3 {get; set;} 
    public int p4 {get; set;} 
} 

現在你的方法Show只是調用GetValues()功能。如果該項目爲BasicProject,則獲取一組值,如果是AdvancedProject,則獲得另一組值。但它永遠不需要知道該屬性是哪種類型。
沒有什麼必須從A繼承。

這是Liskov Substitution Principle的一部分。它基本上說,如果你有一個方法需要一個類型爲A的參數,那麼你可以用從A繼承的任何對象的實例。你不必知道或關心實際類型是什麼。至於你擔心它是A,這就是你需要知道的。