如何创建嵌套的派生类列表

时间:2017-06-21 11:42:58

标签: c# generics casting

我正在编写一个处理WMI对象的应用程序。我有一个Computer类,其List<Component>属性,Component是一个abtract基类,所有派生类都来自MonitorComputerUnit,{ {1}}等等。

考虑到各种各样的WMI对象,我决定第一次使用自定义.NET泛型(我是初学者),这就是代码 - 只是相关的行:

Printer

它工作正常,直到我意识到我想将每个组件视为List本身,因为我需要将多个监视器和/或其他多个设备分开,所以我相应地更改了我的属性和方法:

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); }

我无法理解错误的位置,因为如果我评论最后两行,我可以看到List和List对象是正确创建的,是正确的类型,并填充了预期的数据。

故事的底线:我不明白为什么我不能将error CS1503: Argument 1: cannot convert from 'System.Collections.Generic.List<Machine.Components.Monitor>' to 'System.Collections.Generic.List<Machine.Components.Component>'对象添加到List<Monitor>,而我可以添加{{1对象为List<List<Component>>

3 个答案:

答案 0 :(得分:1)

专门回答你的问题:

  

我不明白为什么我无法添加List&lt; Monitor&gt;反对a   列出&lt; List&lt; Component&gt;&gt;,虽然我可以添加一个Monitor对象   列表&lt;成分&GT;

这与询问您为什么不能将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());
好吧,好吧?不。我们刚刚向Cat添加了dogs,现在包含两个元素; CatDog

现在如果我们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不允许修改,因此它可以支持协方差。

答案 1 :(得分:0)

解决列表清单要求的一种方法是简单地使用List,然后在需要特定类型的所有组件时进行过滤。

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

这样的设计也使得更容易修改这个集合,因为你不必处理第一次添加特定类型的组件的情况,在这种情况下你需要创建和添加子列表。

答案 2 :(得分:-2)

computer.ListOfComponents.Add(monitor.Cast<Component>().ToList());
computer.ListOfComponents.Add(computerUnitCast<Component>().ToList());