2017-06-21 76 views
3

我正在編寫一個應用程序來處理WMI對象。我有一個Computer類與一個List<Component>財產,是Component abtract基類,從中得到所有派生類,如Monitor,ComputerUnit,Printer等。如何創建派生類的嵌套列表

考慮到種類繁多的WMI對象,我決定使用自定義.NET泛型的第一次(我是初學者)的,這是代碼 - 只是相關線路:

public class Computer 
{ 
    public List<Component> ListOfComponents { get; set; } 
} 

public class Component 
{ 
    public NameSpaceBase[] WMI_ClassArray { get; set; } 
} 

public class Monitor : Component 
{ } 

public class ComputerUnit : Component 
{ } 

public static void Main() 
{ 
    Computer computer = new Computer(hostName); 

    Monitor monitor = computer.Get<Monitor>(new NameSpaceBase[] { 
               new WMI_Monitor() }); 

    ComputerUnit computerUnit = computer.Get<ComputerUnit>(
            new NameSpaceBase[] { 
             new WMI_Bios(), 
             new WMI_ComputerSystem() }); 

    computer.ListOfComponents.Add(monitor); 
    computer.ListOfComponents.Add(computerUnit); 
} 

這是工作的罰款,直到我意識到我想對待每一個組件作爲列表本身,因爲我需要有多個顯示器和/或分離等多種設備,因此我適時改變我的屬性和方法:

public class Computer 
{ 
    public List<List<Component>> ListOfComponents { get; set; } 
} 

public static void Main() 
{ 
    Computer computer = new Computer(hostName); 

    List<Monitor> monitor = computer.Get<Monitor>(new NameSpaceBase[] { 
               new WMI_Monitor() }); 

    List<ComputerUnit> computerUnit = computer.Get<ComputerUnit>(
           new NameSpaceBase[] { 
            new WMI_Bios(), 
            new WMI_ComputerSystem() }); 

    computer.ListOfComponents.Add(monitor); 
    computer.ListOfComponents.Add(computerUnit); 
} 

但現在我在la給了error CS1503: Argument 1: cannot convert from 'System.Collections.Generic.List<Machine.Components.Monitor>' to 'System.Collections.Generic.List<Machine.Components.Component>'兩條線。

我不明白錯誤在哪裏,因爲如果我評論最後兩行,我可以看到List和List對象是正確創建的,正確的類型並填充了預期的數據。故事的

底線:我不明白爲什麼我不能添加一個List<Monitor>對象爲List<List<Component>>,而我可以一個Monitor對象添加到List<Component>

+0

這與協方差有關,但我不確定爲什麼它不起作用,因爲列表是協變的。 –

+0

@ rory.ap,因爲協方差僅與接口和委託相關 –

+0

@ rory.ap,不支持類中的協方差 – Rahul

回答

1

具體回答你的問題:

我不明白爲什麼我不能<監視器>對象名單加入一個 列表<名單<組件> >,而我可以將一個Monitor對象添加到 列表<組件>。

這是一樣的問你爲什麼不能分配List<Derived>List<Base>其中Derived : Base

某些語言允許這樣做,但C#沒有。讓我們來看看爲什麼。

考慮這些類:

class Animal 
{ 
} 

class Cat : Animal 
{ 
    public void Meow() {} 
} 

class Dog : Animal 
{ 
    public void Bark() { } 
} 

現在,假設你有狗的清單:

List<Dog> dogs = new List<Dog> {new Dog()}; 

不允許你做到以下幾點:

List<Animal> animals = dogs; // Not allowed - let's pretend it is! 

好吧,讓我們假裝上面的行編譯。執行後,animals列表將參考dogs,這是一個List<Dog>。記住這個重要的事實!

現在讓我們做到以下幾點:

animals.Add(new Cat()); 

似乎好了吧?不。我們剛剛添加了一個Catdogs,它現在包含兩個元素;一個Cat和一個Dog

現在會發生什麼,如果我們做dogs[1].Bark();

答案是該程序會在運行時炸掉,因爲貓不會吠叫!當然,這不可能實際發生,因爲你不允許做List<Animal> animals = dogs;


可能的解決方案?

有一個IReadOnlyList<T> interface,你可以用它代替IList<T>

IReadOnlyList<Animal> animals = dogs; // Compiles OK. 

這是允許的,因爲它被聲明,如下所示:

public interface IReadOnlyList<out T> : IReadOnlyCollection<T>, 
IEnumerable<T>, IEnumerable 

out T指定界面covariant。由於IReadOnlyList不允許修改,所以它可能支持協方差。

+0

更改爲列表>並運行平穩。謝謝! –

-2
computer.ListOfComponents.Add(monitor.Cast<Component>().ToList()); 
computer.ListOfComponents.Add(computerUnitCast<Component>().ToList()); 
+0

任何評論爲什麼這不起作用? –

+0

無論它是否有效,都應該包含一些上下文/解釋。 – EJoshuaS

+0

它的工作,實際上。我沒有下降,但我認爲你的解決方案只是提供了一個設計缺陷的捷徑。但作品! –

0

解決您的List列表需求的一種方法是簡單地使用List,然後在您需要特定類型的所有組件時進行過濾。

monitors = computer.ListOfComponents.OfType<Monitor>(); 

這樣的設計也使得它更容易修改這個集合,因爲你不必處理添加特定類型的第一次的一個組成部分的情況下,在這種情況下,你需要也創建並添加子列表。