这可能是一个非常简单的问题,但对我来说没有意义。
鉴于此课程:
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?
答案 0 :(得分:11)
这称为协方差。 Eric Lippert和Jon Skeet(以及其他人)在这个问题的答案中给出了协方差(以及它的双胞胎,逆变)的一些很好的解释:Difference between Covariance & Contra-variance
非常基本,您可以枚举Person
列表,就像您在ICloneable
列表中所做的那样,不会出现任何问题,因为您可以&#39; t更改枚举。但是,您无法将Person
的列表分配到ICloneable
列表,因为稍后您可以尝试在其中插入ICloneable
的其他衍生物,其中会导致严重违反类型安全。
答案 1 :(得分:5)
public interface IList<T> : ICollection<T>,
IEnumerable<T>, IEnumerable
public interface IEnumerable<out T> : IEnumerable
请注意out
中的IEnumerable
? IEnumerable<T>
是covariant
答案 2 :(得分:2)
我有一个不同的答案,这是错误的。我道歉。感谢Matt指出这一点。
错误消息非常具有误导性。它表明一个演员会工作,但没有。问题是Person转换为ICloneable可能需要调整指针,以便虚拟功能表对于通用ICloneable是正确的。这意味着列表中的每个元素都需要进行调整。真正的解决方法是使用ToList:
IList<ICloneable> clonablesA = people.ToList<ICloneable>();
忽略下面的一些评论,因为我完全删除了我的第一个答案。