【问题标题】:Cannot convert source type 'List<Person>' to IList<ISomething>无法将源类型“List<Person>”转换为 IList<ISomething>
【发布时间】:2014-09-25 19:11:11
【问题描述】:

这可能是一个非常简单的问题,但对我来说没有意义。

鉴于这个类:

public class Person : ICloneable {
    public object Clone()
    {
        Console.WriteLine("Hello, world");
        return new Person();
    }
}

为什么会这样?

List<Person> people = new List<Person> { new Person() };

IEnumerable<ICloneable> clonables = people;

但这不是?

List<Person> people = new List<Person> { new Person() };

IList<ICloneable> clonables = people;

为什么我可以分配给 IEnumerable IClonable,但不能分配给 IList ICloneable?

【问题讨论】:

  • 您收到的错误消息可能已经告诉您原因。
  • IEnumererable&lt;T&gt; 是协变的,这就是它起作用的原因。 List&lt;T&gt; 不是,也不能是。
  • 所以,解决方案是:cloneables = people.Cast&lt;ICloneable&gt;().ToList();
  • 不是一个好的解决方案。你实际上是在创建一个新的List&lt;ICloneable&gt;,而不是重新分配旧的。

标签: c# .net casting


【解决方案1】:

这称为协方差。 Eric Lippert 和 Jon Skeet(以及其他人)在回答这个问题时对协方差(及其孪生体,逆变)给出了一些很好的解释:Difference between Covariance & Contra-variance

非常基本,您可以枚举Person 列表,就像枚举ICloneable 列表一样,不会出现问题,因为您无法更改枚举。但是您不能将您的Person 列表分配给ICloneable 列表,因为之后您可以尝试,例如,在其中插入ICloneable 的一些其他派生词,这将导致严重违反类型-安全。

【讨论】:

    【解决方案2】:

    IList:

    public interface IList<T> : ICollection<T>, 
        IEnumerable<T>, IEnumerable
    

    IEnumerable:

    public interface IEnumerable<out T> : IEnumerable
    

    注意到IEnumerable 中的out 了吗? IEnumerable&lt;T&gt;covariant

    【讨论】:

      【解决方案3】:

      我有一个不同的答案,这是错误的。我道歉。感谢马特指出这一点。

      错误信息非常具有误导性。它表明演员阵容会起作用,但不会。问题是 Person 到 ICloneable 的转换可能需要调整指针,以便虚函数表对于通用 ICloneable 是正确的。这意味着列表中的每个元素都可能需要调整。真正的解决方法是使用 ToList:

              IList<ICloneable> clonablesA = people.ToList<ICloneable>();
      

      忽略下面的一些 cmets,因为我完全删除了我的第一个答案。

      【讨论】:

      • 不要在你的帖子上签名。他们已经签署;看? --------------->
      • 即使是显式转换也不起作用。 IList cloneables = (IList)people;
      • 错误消息没有说存在显式转换,在这种情况下也不是有效的。
      • 使用 VS 2013,我看到的错误消息是:错误 1 ​​无法将类型 'System.Collections.Generic.List' 隐式转换为 'System.Collections.Generic.IList'。存在显式转换(您是否缺少演员表?) C:\Users\Ken\Documents\Visual Studio 2013\Projects\Samples\Cloneable\Cloneable\Program.cs 29 45 Cloneable
      • 显式转换不起作用。它会将您的编译时错误换成运行时异常 (InvalidCastException)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多