我正在编写一个处理WMI对象的应用程序。我有一个Computer
类,其List<Component>
属性,Component
是一个abtract基类,所有派生类都来自Monitor
,ComputerUnit
,{ {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>>
。
答案 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
,现在包含两个元素; 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
由于IReadOnlyList
不允许修改,因此它可以支持协方差。
答案 1 :(得分:0)
解决列表清单要求的一种方法是简单地使用List,然后在需要特定类型的所有组件时进行过滤。
monitors = computer.ListOfComponents.OfType<Monitor>();
这样的设计也使得更容易修改这个集合,因为你不必处理第一次添加特定类型的组件的情况,在这种情况下你需要创建和添加子列表。
答案 2 :(得分:-2)
computer.ListOfComponents.Add(monitor.Cast<Component>().ToList());
computer.ListOfComponents.Add(computerUnitCast<Component>().ToList());