- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
所以,假设我有:
Public Interface ISomeInterface
End Interface
Public Class SomeClass
Implements ISomeInterface
End Class
如果我有 MyList
作为 List(Of SomeClass)
,我不能直接设置 List(Of ISomeInterface) = MyList
。但是,我可以设置 IEnumerable(Of ISomeInterface) = MyList
。
根据我对协方差的理解,我认为它应该可以工作,因为 List(Of T)
实现了 IEnumerable(Of T)
。显然,我错过了一些东西。
为什么会这样?具体为什么我不能这样做:
Dim Animals As new List(Of Animal)
Dim Cats As List(Of IAnimal) = Animals
Animal 实现 IAnimal 接口(interface)的地方。但我可以:
Dim Animals As New List(Of Animal)
Dim Cats As IEnumerable(Of IAnimal) = Animals
最佳答案
我记得以前在网上看到过很多关于这个问题的信息,所以我不确定我的回答是否真的会增加任何新内容,但我会尝试的。
如果您使用的是 .NET 4,请注意 IEnumerable(Of T) 的定义实际上是 IEnumerable(Of Out T)。版本 4 中引入了新的 Out 关键字,表示该接口(interface)的协方差。然而,List(Of T) 类被简单地定义为 List(Of T)。此处未使用 Out 关键字,因此该类不是协变的。
我将提供一些示例来解释为什么某些作业(例如您所描述的作业)无法完成。我看到你的问题是用 VB 写的,所以我很抱歉使用 C#。
假设你有以下类:
abstract class Vehicle
{
public abstract void Travel();
}
class Car : Vehicle
{
public override void Travel()
{
// specific implementation for Car
}
}
class Plane : Vehicle
{
public override void Travel()
{
// specific implementation for Plane
}
}
您可以创建汽车列表,其中只能包含从 Car 派生的对象:
List<Car> cars = new List<Car>();
您还可以创建平面列表,其中只能包含从平面派生的对象:
List<Plane> planes = new List<Plane>();
您甚至可以创建一个 Vehicles 列表,其中可以包含任何从 Vehicle 派生的对象:
List<Vehicle> vehicles = new List<Vehicle>();
将汽车添加到汽车列表中是合法的,将飞机添加到飞机列表中也是合法的。将汽车和飞机都添加到车辆列表中也是合法的。因此,以下所有代码行都是有效的:
cars.Add(new Car()); // add a car to the list of cars
planes.Add(new Plane()); // add a plane to the list of planes
vehicles.Add(new Plane()); // add a plane to the list of vehicles
vehicles.Add(new Car()); // add a car to the list of vehicles
将汽车添加到飞机列表中是不合法的,将飞机添加到汽车列表中也是不合法的。以下代码行无法编译:
cars.Add(new Plane()); // can't add a plane to the list of cars
planes.Add(new Car()); // can't add a car to the list of planes
因此,通过将汽车列表或飞机列表分配给车辆变量来尝试绕过此限制是不合法的:
vehicles = cars; // This is not allowed
vehicles.Add(new Plane()); // because then you could do this
考虑上面两行代码的含义。据说车辆变量实际上是List<Car>
对象,它应该只包含从 Car 派生的对象。但是,因为 List<Vehicle>
包含 Add(Vehicle) 方法,理论上可以将 Plane 对象添加到 List<Car>
收藏,这绝对是不正确的。
但是,将汽车列表或飞机列表分配给 IEnumerable<Vehicle>
是完全有效的。变量。
IEnumerable<Vehicle> vehicles = cars;
foreach (Vehicle vehicle in vehicles)
{
vehicle.Travel();
}
这里的快速解释是 IEnumerable 接口(interface)不允许您操作集合。它本质上是一个只读接口(interface)。 T 对象(在本例中为车辆)仅作为 IEnumerable 接口(interface)的 Current 属性的返回值公开。没有将 Vehicle 对象作为输入参数的方法,因此不存在非法修改集合的危险。
旁注:我一直认为 IList<T>
是有意义的。接口(interface)是 IReadableList<out T>
的组合接口(interface)和 IWritableList<in T>
界面。
关于.net - List 与 IEnumerable 的协变和逆变,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8565732/
COW 不是奶牛,是 Copy-On-Write 的缩写,这是一种是复制但也不完全是复制的技术。 一般来说复制就是创建出完全相同的两份,两份是独立的: 但是,有的时候复制这件事没多大必要
我是一名优秀的程序员,十分优秀!