[英]Generics List<List<T>>
If I have List<T>
which got some lists from type MyClass
, for example List<List<MyClass>>
and MyClass
is the parent class from MyClassB
. 如果我有
List<T>
,它从MyClass
类型中得到了一些列表,例如List<List<MyClass>>
和MyClass
是MyClassB
的父类。 Why I can't do the following? 为什么我不能执行以下操作?
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);
If I implement a method I can say SomeClass<T> ... where T : MyClass
, is there something similar for my list problem? 如果我实现一个方法,我可以说
SomeClass<T> ... where T : MyClass
,列表问题是否有类似的东西?
So that I can add lists from any child class to my first-level list? 这样我可以将任何子类的列表添加到我的第一级列表中?
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!
Your question is "why is that illegal?" 您的问题是“为什么这是违法的?” The answer is: suppose it were legal and let's keep going...
答案是:假设这是合法的,那就继续吧...
List<Animal> animals = lists[0]; // Obviously typesafe.
animals.Add(new Tiger()); // Obviously typesafe
And we just added a tiger to a list of giraffes. 我们只是将老虎添加到了长颈鹿列表中。
Since the two latter steps are obviously typesafe, the place that cannot be typesafe must be Add(giraffes)
. 由于后面两个步骤显然是类型安全的,因此不能类型安全的地方必须是
Add(giraffes)
。
Now, as of C# 4, this does work: 现在,从C#4开始,它确实起作用:
List<IEnumerable<Animal>> lists = new List<IEnumerable<Animal>>();
lists.Add(giraffes);
Why is that legal? 为什么那是合法的? Because there is no
Add
method on IEnumerable<T>
: 因为
IEnumerable<T>
上没有Add
方法:
IEnumerable<Animal> animals = lists[0];
And now we can't violate type safety because there's no way to put a tiger into that list of giraffes if we only are accessing it via IEnumerable<T>
. 现在我们不能违反类型安全性,因为如果仅通过
IEnumerable<T>
访问它,就无法将老虎放入该长颈鹿列表。
By the way, someone asks this question almost every day. 顺便说一句,几乎每天都有人问这个问题。 Do a web search for "C# covariance and contravariance" and you'll get a lot more information about it.
在网络上搜索“ C#协方差和逆方差”,您将获得有关它的更多信息。
The reason that you cannot do it is as follows: imagine that allLists.Add(myList)
worked. 您无法执行此操作的原因如下:假设
allLists.Add(myList)
有效。 Then the compiler would know that allLists[0]
is a List<MyClass>
, so the following would be OK: 然后,编译器将知道
allLists[0]
是List<MyClass>
,因此allLists[0]
以下条件:
allLists[0].Add(new MyClassX());
That would be a runtime error, because allLists[0]
is actually a List<MyClassB>
. 那将是一个运行时错误,因为
allLists[0]
实际上是List<MyClassB>
。 It is not capable of holding MyClassX
objects. 它不能容纳
MyClassX
对象。
If you change your code so that myList
is a List<MyClass>
, your code would work: 如果更改代码,使
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>>();
the list you are adding is the not same type. 您要添加的列表不是同一类型。 You may do like this:
您可能会这样:
interface IMyClass
{
//some properties
}
All your child classes must inherit from IMyClass. 您的所有子类都必须继承自IMyClass。 Then you will have list like this.
然后,您将获得像这样的列表。
List<List<IMyClass>> allLists = new List<List<IMyClass>>();
The problem is that AllLists is strongly-typed to contain lists of MyClass. 问题是AllLists是强类型的,以包含MyClass的列表。 MyList is strongly-typed to contain instances of MyClassB.
MyList是强类型的,以包含MyClassB的实例。
Whereas you'd be able to store List in your List>, there is a type mismatch in your current code. 尽管您可以将List存储在List>中,但是当前代码中的类型不匹配。
这将解决问题:
List<MyClass> myList = new List<MyClass>();
You need to tell the compiler that MyClass is the parent from MyClassB i think. 您需要告诉编译器,我认为MyClass是MyClassB的父级。 This article about the
where
keyword may help you further 这篇有关
where
关键字的文章可能会进一步帮助您
Even though MyClassB is a sub type of MyClass, it doesn't mean that List is a sub type of List. 即使MyClassB是MyClass的子类型,也并不意味着List是List的子类型。 The question you want to ask is why List isn't covariant with T (which would cause List to be a subtype of List where T is a subtype of Y. Look up the terms covariance and contravariance.
您要问的问题是为什么List与T不协变(这将导致List成为List的子类型,其中T是Y的子类型。请查找协方差和对数。
The answer is two fold. 答案有两个。 Firstly List was implemented before C# implemented co- and contravariance.
首先,在C#实施协和反方差之前先实施List。 But most importantly, you can only be covariant if T is an "out" type.
但最重要的是,仅当T为“输出”类型时才可以协变。 Since you can shove stuff into a list, it is not an out type.
由于您可以将内容推入列表,因此它不是out类型。 IEnumerable only emits objects of type T. Therefore, it can be covariant.
IEnumerable仅发出类型为T的对象。因此,它可以是协变的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.