List .AddRange(List )不起作用

我发现无法将具体对象列表添加到接口对象列表中。

public static void AddJob(List masterJobs, List jobs) { masterJobs.AddRange(jobs); //fail to compile } 

相反,需要使用以下代码:

 public static void AddJob(List masterJobs, List jobs) { masterJobs.AddRange(jobs.Cast()); } 

这背后的理性是什么?

Lasse对于为什么这在C#3中不起作用是正确的 – 没有从ListList

在C#4中,它可以工作,不是因为列表是协变的,而是因为IEnumerable是协变的。 换句话说,代码实际上是:

 public static void AddJob(List masterJobs, List jobs) { IEnumerable jobsTmp = jobs; // This is the covariance working masterJobs.AddRange(jobs); // This is now fine } 

jobs实现了IEnumerable ,因此通过协方差有一个IEnumerable的引用转换,所以一切正常。 对Cast的调用实际上是在C#3解决方法中执行类似的工作 – 您正在使用它来转换为IEnumerable

如果你想了解更多关于generics差异的信息,可以看一下我的NDC 2010演讲video ,或者阅读Eric Lippert的一系列博客文章 。

原因是List不是List ,尽管Job实现了IJob

这是共同或反对的变化(我永远不会记得哪个是哪个。)

思路是这样的:

编译器不能保证AddRange只从给定的参数中读取内容,因此无法保证这是安全的,因此无法编译。

例如,对于所有编译器都知道,AddRange可以将另一个对象添加到jobs参数中,该参数实现IJob (因为AddRange需要IJob集合),但不是Job ,这是jobs期望的,因此这是不安全的。

在C#4.0中,有一些支持处理这个,但我不确定它是否会处理你的特定情况,因为必须在接口级指定支持,而不是在方法级指定。

换句话说,您必须在接口类型上指定与T相关的所有内容仅进入集合,永远不会出现,然后编译器将允许您执行此操作。 但是,您无法阅读的集合将毫无意义。