C# 通用协方差编译时安全检查
C# 通用协方差编译时安全检查,c#,generics,covariance,C#,Generics,Covariance,List在t上不协变,而IEnumerable在t上协变的原因通常通过这样的示例来说明 鉴于以下类别: public class Fruit { } public class Apple : Fruit { } public class Banana : Fruit { } 以下是允许的: public void Permitted() { IEnumerable<Fruit> bananas = new List<Banana> {
List
在t
上不协变,而IEnumerable
在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.
}
}
允许公开作废()
{
IEnumerable香蕉=新列表
{
新香蕉(),
新香蕉(),
新香蕉(),
};
foreach(香蕉中的水果香蕉)
{
//这一切都很好,因为香蕉是一种水果和水果
//我们可以这样对待它。
}
}
以下是不允许的:
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漏洞()
{
//我又高兴了
IEnumerable香蕉=新列表
{
新香蕉(),
新香蕉(),
新香蕉(),
};
//…现在我们可以在香蕉列表中添加一个苹果
香蕉.ToList().Add(新苹果());
}
当然,我们可以这样做:
public void AlsoAllowed()
{
var fruit = new List<Fruit>();
fruit.Add(new Apple());
fruit.Add(new Banana());
}
public void也被允许()
{
var fruit=新列表();
添加(新苹果());
水果。添加(新香蕉());
}
List
不协变(据我理解)的常见理由是,这样做将允许我们向包含派生对象的集合中添加任意基本对象。也许这过于简单化了,但上面的例子不就是这么做的吗?当你做香蕉时,ToList().Add(new Apple())
,香蕉。ToList()
创建一个列表。这是一个列表类型,可以包含任何类型的水果。newapple()
可以添加到该列表中这一事实是有道理的
香蕉
具有类型列表
,该列表类型只能包含香蕉。无法将new Apple()
添加到此列表中,您的示例也不会将new Apple()
添加到此列表中。您的示例创建了一个更宽容的列表,并添加到该列表中,但保留原始列表不变。当您执行香蕉时,ToList().add(new Apple())
,香蕉。ToList()
创建一个列表。这是一个列表类型,可以包含任何类型的水果。newapple()
可以添加到该列表中这一事实是有道理的
香蕉
具有类型列表
,该列表类型只能包含香蕉。无法将new Apple()
添加到此列表中,您的示例也不会将new Apple()
添加到此列表中。您的示例创建了一个更宽容的列表,并将其添加到该列表中,但保留原始列表不变。仅添加到该列表中,在第二个示例中,将苹果
s和香蕉
s添加到水果
中绝对没有错。水果不仅被键入,而且被实例化为列表
,在第二个示例中,将Apple
s和Banana
s添加到fruit
中绝对没有错,后者不仅被键入,而且被实例化为列表。