[英]Generic covariance compile time safety checks
为什么原因List<T>
未在协变T
,而IEnumerable<T>
是上协变T
通常是由这样一个例子来说明。
给定以下类别:
public class Fruit
{
}
public class Apple : Fruit
{
}
public class Banana : Fruit
{
}
允许以下内容:
public void Permitted()
{
IEnumerable<Fruit> bananas = new List<Banana>
{
new Banana(),
new Banana(),
new Banana(),
};
foreach (Fruit banana in bananas)
{
// This is all good, because a banana "is a" fruit and
// we can treat it as such.
}
}
以下是不允许的:
public void Disallowed()
{
// Compiler rejects this!
List<Fruit> bananas = new List<Banana>
{
new Banana(),
new Banana(),
new Banana(),
};
// ...Otherwise we can add an apple to a list containing bananas
bananas.Add(new Apple());
}
但是,我们仍然可以通过执行以下操作来实现:
public void Loophole()
{
// Compiler is happy again
IEnumerable<Fruit> bananas = new List<Banana>
{
new Banana(),
new Banana(),
new Banana(),
};
// ...And now we can add an apple to a list of bananas
bananas.ToList().Add(new Apple());
}
当然,我们可以这样做:
public void AlsoAllowed()
{
var fruit = new List<Fruit>();
fruit.Add(new Apple());
fruit.Add(new Banana());
}
List<T>
协变量不是协变的(据我的理解)是这样做可以使我们向包含派生对象的集合中添加任意基础对象。 也许这是一个过分的简化,但这不是上面的示例正在做的事情吗?
当您执行bananas.ToList().Add(new Apple())
, bananas.ToList()
创建List<Fruit>
。 这是一个列表类型,可以包含任何类型的水果。 可以将new Apple()
添加到该列表中的事实很有意义。
bananas
类型为List<Banana>
,这是一个只能包含香蕉的列表类型。 无法将new Apple()
添加到此列表,并且您的示例也没有将new Apple()
添加到此列表。 您的示例将创建一个更宽容的列表,然后添加到列表中,但保留原始列表不变。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.