代码之家  ›  专栏  ›  技术社区  ›  Graviton

List<IJob>.AddRange(List<Job>)不起作用

  •  5
  • Graviton  · 技术社区  · 14 年前

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

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

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

    2 回复  |  直到 14 年前
        1
  •  10
  •   Jon Skeet    14 年前

    List<IJob> List<Job> .

    在C#4中它会起作用,不是因为 IEnumerable<T> 是协变的。换句话说,代码实际上是:

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

    jobs IEnumerable<Job> ,所以有一个引用转换为 IEnumerable<IJob> 通过协方差,所以一切正常。呼叫 Cast<T> IEnumerable<IJob> .

    video of my NDC 2010 talk series of blog posts 在上面。

        2
  •  8
  •   Lasse V. Karlsen    14 年前

    List<IJob> 不是一个 List<Job> ,虽然 Job 工具 IJob

    这是协方差或逆方差(我从不记得哪个是哪个。)

    思路是这样的:

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

    例如,就编译器所知,AddRange可以将另一个对象添加到 jobs 参数,实现 伊霍布 (因为AddRange期望 收藏),但不是 工作 工作

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

    换句话说,您必须在接口类型上指定与T相关的所有内容只进入集合,而不是从集合中出来,然后编译器将允许您这样做。然而,一个你不能从中读取的集合是毫无意义的。