2017-03-08 35 views
1

試圖幫助一個朋友在這裏。我不是微軟的程序員。創建一個抽象基類的數組或列表或子集

public abstract class Foo {} 
public class Bar : Foo {} 
public class Baz : Foo {} 

這似乎是工作得很好,然後在另一個類,他可以實例的Bar陣列,並Baz這樣

public class MyClass { 
    Bar[] Bars = new Bar[] { new Bar[] { new Bar(), new Bar() } } 
    Baz[] Bazs = new Baz[] { new Baz[] { new Baz(), new Baz() } } 
} 

的問題是,如果他想有一個返回FoosBars的訪問他是怎麼做的?

public class MyClass { 
    Bar[] Bars = new Bar[] { new Bar[] { new Bar(), new Bar() } } 
    Baz[] Bazs = new Baz[] { new Baz[] { new Baz(), new Baz() } } 
    public IEnumerable<Foo> GetFoos() { 
    // No go. 
    return [ Bars, Bazs ]; 

    // Also No go. 
    List<Foo> test = new List<Foo> { Bars, Bazs }; 
    return test; 
    } 
} 

我認爲微軟通常使用接口來實現這一點,但他的任務需要使用抽象基類。有沒有辦法返回一個抽象基類的List或Array的子​​元素?

+0

在這兩種情況下,你可以'創建'new Foo()'的實例,因爲'Foo'是一個抽象類。您可以創建Bar和Baz的對象並返回一個Foo數組。看下面的答案是否有幫助。 –

+0

在代碼中出現語法錯誤:使用Bar [] Bars = new Bar [] {new Bar(),new Bar()}創建一個數組,您似乎創建了一些嵌套數組,新酒吧[] {新酒吧[] {...' – HugoRune

回答

0

在這兩種情況下,您都不能創建'new Foo()'的實例,因爲'Foo'是一個抽象類。您可以創建Bar和Baz的對象並返回一個Foo數組。看下面的答案是否有幫助。

public class MyClass 
    { 
     Foo[] Foos1 = new Foo[] { new Bar(), new Bar() }; 
     Foo[] Foos2 = new Foo[] { new Baz(), new Baz() }; 

     // OR use as below 

     /* 
     Foo[] Foos1 = new Bar[] { new Bar(), new Bar() }; 
     Foo[] Foos2 = new Baz[] { new Baz(), new Baz() }; 
     */ 

     public IEnumerable<Foo> GetFoos1() 
     { 
      // Works. 
      return Foos1; 
     } 

     public IEnumerable<Foo> GetFoos2() 
     { 
      // Works 
      List<Foo> test = new List<Foo>(); 
      test.AddRange(Foos2); 
      return test; 
     } 
    } 
+0

是否有任何保持Foos1和Foos2在代碼點的強烈類型,並使其仍然工作?或者,我有沒有將它們輸入ABC? –

+0

不清楚,如果我明白瞭解問題。如果你可以解釋你想要解決的問題/場景,那將會很有幫助。您也可以更換上述問題的前兩行,如更新後的答案。 –

+0

在這種情況下,如果我想聲明Foos1爲Bar []類型,那麼在從函數返回的點之前丟失了鍵入信息 - 當您聲明該'Foo [] Foos1'時,我可以在那時執行該操作然後後來施放什麼東西到Foo? –

0

爲了另一個IEnumerable'T添加到列表中,你必須使用「的AddRange」,如:

List<Foo> test = new List<Foo>(); 
test.AddRange(Foos); 
test.AddRange(Bars); 

return test; 

您也可以使用列表構造函數重載,以增加現有的IEnumerable」 T到您的列表:

List<Foo> test = new List<Foo>(Foos); 
test.AddRange(Bars); 

return test; 
+0

底部不起作用,因爲Foo是抽象基類,沒有構造函數。 –

0

有沒有必要複製你的數組。下面的代碼將產生一個IEnumerable<Foo>是始終反映陣列的當前內容,並且不消耗內存的任何顯著量:

public class MyClass 
{ 
    private Bar[] Bars = new Bar[] {new Bar(), new Bar()}; 
    private Baz[] Bazs = new Baz[] {new Baz(), new Baz()}; 

    public IEnumerable<Foo> GetFoos() 
    { 
     // Cast Bars as an Enumerable<Foo>, then append Bazs 
     // (no need to explicitly cast Bazs) 
     return Bars.AsEnumerable<Foo>().Concat(Bazs); 

     // or 

     // Create an empty Enumerable<Foo>, then append Bazs and Bars 
     return Enumerable.Empty<Foo>().Concat(Bars).Concat(Bazs); 
    } 
} 

由GetFoos返回(對象),這裏僅僅是兩個原始參考陣列。每當代碼枚舉這個IEnumerable時,它將隱式地訪問兩個原始數組。因此,如果在調用GetFoos()之後,但在使用結果表單GetFoos()之前,某人用NULL替換Bars的每個項目,那麼調用GetFoos()的代碼將只看到一堆NULL。

如果你不想返回的IEnumerable的內容,只要你改變原來陣列的內容改變,你將需要創建一個副本,就像這樣:

public IEnumerable<Foo> GetFoos() 
{ 
    return Enumerable.Empty<Foo>().Concat(Bars.ToArray()).Concat(Bazs.ToArray()); 
}