本文介绍了协方差与List对比IEnumerable的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因此,假设我有:

Public Interface ISomeInterface

End Interface

Public Class SomeClass
  Implements ISomeInterface

End Class

如果我有 MyList 作为 List(Of SomeClass),则不能直接设置 List(Of ISomeInterface)= MyList 。但是,我可以设置 IEnumerable(Of ISomeInterface)= MyList

If I have MyList as List(Of SomeClass), I cannot directly set a List(Of ISomeInterface) = MyList. However, I can Set an IEnumerable(Of ISomeInterface) = MyList.

根据我对协方差的理解,我认为它应该工作在列表中,因为 List(T)实现了 IEnumerable(T)。显然,我缺少了一些东西。

With my understanding of Covariance I thought that it should work list to list since List(Of T) implements IEnumerable(Of T). Clearly, I am missing something.

为什么这样工作?具体地说,为什么我不能做这样的事情:

Why does it work that way? Specifically why Can't I do something like:

Dim Animals As new List(Of Animal)
Dim Cats As List(Of IAnimal) = Animals

其中Animal实现了IAnimal接口的地方。但我可以:

Where Animal implements the IAnimal Interface. But I can do:

Dim Animals As New List(Of Animal)
Dim Cats As IEnumerable(Of IAnimal) = Animals


推荐答案

我记得看到了很多与此有关的信息

I recall seeing a lot of information around this issue on the web previously, so I'm not sure that my answer will really add anything new, but I'll try.

如果您使用的是.NET 4,那么我不确定我的答案是否会真正添加新内容,但我会尽力而为。 ,然后注意IEnumerable(Of T)的定义实际上是IEnumerable(Of T)。在版本4中引入了新的Out关键字,它指示此接口的协方差。但是,List(Of T)类仅定义为List(Of T)。这里不使用Out关键字,因此该类不是协变的。

If you're using .NET 4, then notice that the definition of IEnumerable(Of T) is actually IEnumerable(Of Out T). The new Out keyword has been introduced in version 4, which indicates the covariance of this interface. The List(Of T) class, however, is simply defined as List(Of T). The Out keyword is not used here, so that class is not covariant.

我将提供一些示例来尝试解释为什么某些作业(例如您所分配的作业)描述无法完成。我看到您的问题是用VB编写的,因此我对使用C#表示歉意。

I'll provide some examples to try to explain why certain assignments such as the one you're describing can't be done. I see that your question is written in VB, so my apologies for using 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的对象:

You can create a list of cars, which can only contain objects derived from Car:

        List<Car> cars = new List<Car>();

您还可以创建一个平面列表,其中只能包含从平面派生的对象:

You can also create a list of planes, which can only contain objects derived from Plane:

        List<Plane> planes = new List<Plane>();

您甚至可以创建一个Vehicles列表,其中可以包含任何衍生自Vehicle的对象:

You can even create a list of Vehicles, which can contain any object derived from Vehicle:

        List<Vehicle> vehicles = new List<Vehicle>();

在汽车清单中添加汽车是合法的,在飞机列表中添加飞机是合法的飞机清单。将汽车和飞机都添加到车辆列表中也是合法的。因此,以下所有代码行均有效:

It's legal to add a car to the list of cars, and it's legal to add a plane to the list of planes. It's also legal to add both a car and a plane to the list of vehicles. Therefore, all of the following lines of code are valid:

        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

将汽车添加到以下列表中是不合法的飞机,将飞机添加到汽车列表中也不合法。以下代码行将无法编译:

It's not legal to add a car to the list of planes, nor is it legal to add a plane to the list of cars. The following lines of code won't compile:

        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

因此,尝试这样做是不合法的通过将车辆列表或飞机列表分配给车辆变量来绕过此限制:

Therefore, it's not legal to try to bypass this restriction by assigning the list of cars or the list of planes to the vehicles variable:

        vehicles = cars; // This is not allowed
        vehicles.Add(new Plane()); // because then you could do this

请考虑上面两行代码的含义。就是说,vehicles变量实际上是 List< Car> 对象,该对象应仅包含从Car派生的对象。但是,由于 List< Vehicle> 包含Add(Vehicle)方法,因此理论上可以将Plane对象添加到 List< Car>中。 集合,这绝对是不正确的。

Consider what the two lines of code are saying above. It's saying that the vehicles variable is actually a List<Car> object, which should only contain objects derived from Car. However, because List<Vehicle> contains an Add(Vehicle) method, it would theoretically be possible to add a Plane object to the List<Car> collection, which is definitely not correct.

但是,将汽车列表或飞机列表分配给<$完全正确c $ c> IEnumerable< Vehicle> 变量。

However, it's perfectly valid to assign a list of cars or a list of planes to an IEnumerable<Vehicle> variable.

        IEnumerable<Vehicle> vehicles = cars;

        foreach (Vehicle vehicle in vehicles)
        {
            vehicle.Travel();
        }

这里的快速解释是IEnumerable接口不允许您操作集合。它本质上是一个只读接口。 T对象(在这种情况下为车辆)仅在IEnumerable接口的Current属性中作为返回值公开。没有方法将Vehicle对象作为输入参数,因此不存在以非法方式修改集合的危险。

The quick explanation here is that the IEnumerable interface doesn't allow you to manipulate the collection. It is essentially a read-only interface. The T objects (Vehicles in this case) are only exposed as a return value on the IEnumerable interface's Current property. There are no methods that take Vehicle objects as input parameters, therefore there is no danger of the collection being modified in an illegal way.

侧面说明:我一直认为将 IList< T> 接口组合为 IReadableList< out T> 接口的组合才有意义和 IWritableList< in T> 接口。

Side Note: I've always thought that it would make sense for the IList<T> interface to be a composite of an IReadableList<out T> interface and an IWritableList<in T> interface.

这篇关于协方差与List对比IEnumerable的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-28 22:11