繁体   English   中英

泛型列表 <List<T> &gt;

[英]Generics List<List<T>>

如果我有List<T> ,它从MyClass类型中得到了一些列表,例如List<List<MyClass>>MyClassMyClassB的父类。 为什么我不能执行以下操作?

List<List<MyClass>> allLists = new List<List<MyClass>>();

List<MyClassB> myList = new List<MyClassB>();
myList.Add(new MyClassB());

//And now the point which dont work
allLists.Add(myList);

如果我实现一个方法,我可以说SomeClass<T> ... where T : MyClass ,列表问题是否有类似的东西?

这样我可以将任何子类的列表添加到我的第一级列表中?

class Animal {}
class Tiger : Animal {}
class Giraffe : Animal {}
...
List<Giraffe> giraffes = new List<Giraffe>();
List<List<Animal>> lists = new List<List<Animal>>();
lists.Add(giraffes); // Illegal!

您的问题是“为什么这是违法的?” 答案是:假设这是合法的,那就继续吧...

List<Animal> animals = lists[0]; // Obviously typesafe.
animals.Add(new Tiger()); // Obviously typesafe

我们只是将老虎添加到了长颈鹿列表中。

由于后面两个步骤显然是类型安全的,因此不能类型安全的地方必须是Add(giraffes)

现在,从C#4开始,它确实起作用:

List<IEnumerable<Animal>> lists = new List<IEnumerable<Animal>>();
lists.Add(giraffes);

为什么那是合法的? 因为IEnumerable<T>上没有Add方法:

IEnumerable<Animal> animals = lists[0];

现在我们不能违反类型安全性,因为如果仅通过IEnumerable<T>访问它,就无法将老虎放入该长颈鹿列表。

顺便说一句,几乎每天都有人问这个问题。 在网络上搜索“ C#协方差和逆方差”,您将获得有关它的更多信息。

您无法执行此操作的原因如下:假设allLists.Add(myList)有效。 然后,编译器将知道allLists[0]List<MyClass> ,因此allLists[0]以下条件:

allLists[0].Add(new MyClassX());

那将是一个运行时错误,因为allLists[0]实际上是List<MyClassB> 它不能容纳MyClassX对象。

如果更改代码,使myListList<MyClass> ,则代码将起作用:

List<MyClass> myList = new List<MyClass>();
myList.Add(new MyClassB()); // This works, because MyClassB extends MyClass
allLists.Add(myList); // This works, too

您必须使用允许派生类的接口(称为协变接口 )作为内部集合:

var allLists = new List<IEnumerable<MyClass>>();
List<List<MyClass>> allLists = new List<List<MyClass>>();

您要添加的列表不是同一类型。 您可能会这样:

interface IMyClass
{
    //some properties
}

您的所有子类都必须继承自IMyClass。 然后,您将获得像这样的列表。

List<List<IMyClass>> allLists = new List<List<IMyClass>>();

问题是AllLists是强类型的,以包含MyClass的列表。 MyList是强类型的,以包含MyClassB的实例。

尽管您可以将List存储在List>中,但是当前代码中的类型不匹配。

这将解决问题:

List<MyClass> myList = new List<MyClass>();

您需要告诉编译器,我认为MyClass是MyClassB的父级。 这篇有关where关键字的文章可能会进一步帮助您

即使MyClassB是MyClass的子类型,也并不意味着List是List的子类型。 您要问的问题是为什么List与T不协变(这将导致List成为List的子类型,其中T是Y的子类型。请查找协方差和对数。

答案有两个。 首先,在C#实施协和反方差之前先实施List。 但最重要的是,仅当T为“输出”类型时才可以协变。 由于您可以将内容推入列表,因此它不是out类型。 IEnumerable仅发出类型为T的对象。因此,它可以是协变的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM