[英]Generics List<List<T>>
如果我有List<T>
,它从MyClass
类型中得到了一些列表,例如List<List<MyClass>>
和MyClass
是MyClassB
的父类。 为什么我不能执行以下操作?
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
对象。
如果更改代码,使myList
为List<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>();
即使MyClassB是MyClass的子类型,也并不意味着List是List的子类型。 您要问的问题是为什么List与T不协变(这将导致List成为List的子类型,其中T是Y的子类型。请查找协方差和对数。
答案有两个。 首先,在C#实施协和反方差之前先实施List。 但最重要的是,仅当T为“输出”类型时才可以协变。 由于您可以将内容推入列表,因此它不是out类型。 IEnumerable仅发出类型为T的对象。因此,它可以是协变的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.