无法将源类型“List <person>”转换为IList <isomething> </isomething> </person>

时间:2014-09-25 19:11:11

标签: c# .net casting

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

鉴于此课程:

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?

3 个答案:

答案 0 :(得分:11)

这称为协方差。 Eric Lippert和Jon Skeet(以及其他人)在这个问题的答案中给出了协方差(以及它的双胞胎,逆变)的一些很好的解释:Difference between Covariance & Contra-variance

非常基本,您可以枚举Person列表,就像您在ICloneable列表中所做的那样,不会出现任何问题,因为您可以&#39; t更改枚举。但是,您无法将Person的列表分配到ICloneable列表,因为稍后您可以尝试在其中插入ICloneable的其他衍生物,其中会导致严重违反类型安全。

答案 1 :(得分:5)

IList

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

IEnumerable

public interface IEnumerable<out T> : IEnumerable

请注意out中的IEnumerableIEnumerable<T>covariant

答案 2 :(得分:2)

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

错误消息非常具有误导性。它表明一个演员会工作,但没有。问题是Person转换为ICloneable可能需要调整指针,以便虚拟功能表对于通用ICloneable是正确的。这意味着列表中的每个元素都需要进行调整。真正的解决方法是使用ToList:

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

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