泛型列表<;列表<;T>>

本文关键字:gt lt 列表 泛型 | 更新日期: 2023-09-27 18:05:02

如果我有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,那么对于我的列表问题,有类似的东西吗?

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

泛型列表<;列表<;T>>

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].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>();

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

尽管MyClassB是MyClass的子类型,但这并不意味着List是List的子类型。你想问的问题是,为什么List与t不是协变的(这会导致List是List的一个子类型,其中t是Y的子类型

答案是双重的。在C#实现协同和逆变之前,首先实现了List。但最重要的是,只有当T是"out"类型时,你才能是协变的。既然你可以把东西塞进一个列表,它就不是一个out类型。IEnumerable只发出T类型的对象。因此,它可以是协变的。