为什么我不能分配 List<Derived>到列表&lt;基&gt;? [英] Why can&#39;t I assign a List&lt;Derived&gt; to a List&lt;Base&gt;?

查看:22
本文介绍了为什么我不能分配 List<Derived>到列表&lt;基&gt;?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我定义了以下类:

public abstract class AbstractPackageCall
    {

     ...

    }

我还定义了这个类的一个子类:

I also define a subclass of this class:

class PackageCall : AbstractPackageCall
    {

      ...
    }

AbstractPackageCall还有其他几个子类

现在我要拨打以下电话:

Now I want to make the following call:

 List<AbstractPackageCall> calls = package.getCalls();

但我总是得到这个例外:

But I always get this exception:

Error   13  Cannot implicitly convert type 'System.Collections.Generic.List<Prototype_Concept_2.model.PackageCall>' to 'System.Collections.Generic.List<Prototype_Concept_2.model.AbstractPackageCall>' 

这里有什么问题?这是方法 Package#getCalls

What is the problem here? This is the method Package#getCalls

 internal List<PackageCall> getCalls()
        {
            return calls;
        }

推荐答案

理解为什么不允许这样做的最简单方法是以下示例:

The simplest way to understand why this is not allowed is the following example:

abstract class Fruit
{
}

class Apple : Fruit
{
}

class Banana : Fruit
{
}

// This should intuitively compile right? Cause an Apple is Fruit.
List<Fruit> fruits = new List<Apple>();

// But what if I do this? Adding a Banana to a list of Apples
fruits.Add(new Banana());

最后一条语句会破坏 .NET 的类型安全.

The last statement would ruin the type safety of .NET.

然而,数组允许这样做:

Arrays however, do allow this:

Fruit[] fruits = new Apple[10]; // This is perfectly fine

但是,将 Banana 放入 fruits 仍然会破坏类型安全,因此 .NET 必须对每个数组插入进行类型检查,如果是,则抛出异常实际上不是 Apple.这可能是一个(小)性能损失,但是可以通过围绕任一类型创建 struct 包装器来规避这一点,因为此检查不会对值类型进行(因为它们不能从任何东西继承).起初,我不明白为什么做出这个决定,但是您会经常遇到为什么这会很有用.最常见的是 String.Format,它接受 params object[] 并且可以将任何数组传递给它.

However, putting a Banana into fruits would still break type safety, so therefor .NET has to do a type check on every array insertion and throw an exception if it's not actually an Apple. This is potentially a (small) performance hit, but this can be circumvented by creating a struct wrapper around either type as this check does not happen for value types (because they can't inherit from anything). At first, I didn't understand why this decision was made, but you'll encounter quite often why this can be useful. Most common is String.Format, which takes params object[] and any array can be passed into this.

虽然在 .NET 4 中,有类型安全的协变/逆变,它允许您进行一些这样的分配,但前提是它们被证明是安全的.什么是安全的?

In .NET 4 though, there's type safe covariance/contravariance, which allows you to make some assignments like these, but only if they're provably safe. What's provably safe?

IEnumerable<Fruit> fruits = new List<Apple>();

以上在 .NET 4 中有效,因为 IEnumerable 变成了 IEnumerable.out 意味着 T 只能从 fruitsout 并且 根本没有方法IEnumerable 上,它以 T 作为参数,所以你永远不会错误地传递 Banana 进入 IEnumerable.

The above works in .NET 4, because IEnumerable<T> became IEnumerable<out T>. The out means that T can only ever come out of fruits and that there's no method at all on IEnumerable<out T> that ever takes T as a parameter, so you can never incorrectly pass a Banana into IEnumerable<Fruit>.

逆变大致相同,但我总是忘记它的确切细节.不出所料,对于类型参数,现在有了 in 关键字.

Contravariance is much the same but I always forget the exact details on it. Unsurprisingly, for that there's now the in keyword on type parameters.

这篇关于为什么我不能分配 List<Derived>到列表&lt;基&gt;?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆