简体   繁体   English

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

[英]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>>MyClassMyClassB的父类。 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: 如果更改代码,使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>>();

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.

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