无法将源类型"List <Person>"转换为IList <ISomething>

Xin*_*nbi 7 .net c# casting

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

鉴于此类:

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

为什么这样可以?

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

IEnumerable<ICloneable> clonables = people;
Run Code Online (Sandbox Code Playgroud)

但这不是吗?

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

IList<ICloneable> clonables = people;
Run Code Online (Sandbox Code Playgroud)

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

Pat*_*ide 11

这称为协方差.Eric Lippert和Jon Skeet(以及其他人)对这个问题的答案给出了协方差(以及它的双重,逆变)的一些很好的解释:协方差和对立方差之间的差异

基本上,您可以枚举一个列表,Person就像您在列表中一样ICloneable,不会发生任何问题,因为您无法更改枚举.但是你不能将你的列表分配给Person列表,ICloneable因为那时你可以稍后尝试插入其中的一些其他衍生物ICloneable,这将导致严重违反类型安全.


Mat*_*and 5

IList:

public interface IList<T> : ICollection<T>, 
    IEnumerable<T>, IEnumerable
Run Code Online (Sandbox Code Playgroud)

IEnumerable:

public interface IEnumerable<out T> : IEnumerable
Run Code Online (Sandbox Code Playgroud)

注意outIEnumerableIEnumerable<T>协变的