考虑代码段。
IList<String> obj=new List<string>();
IEnumerable<Object> obj1 = obj;
但如果我写ICollection<Object> obj2 = obj;
,它会抛出编译时错误。
无法将类型“
System.Collections.Generic.IList<string>
”隐式转换为“System.Collections.Generic.ICollection<object>
”。
为什么此行为自List<T>
同时实现IEnumerable<T>
和ICollection<T>
以及IList<T>
定义为
public interface IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable
{
T this[int index] { get; set; }
int IndexOf(T item);
void Insert(int index, T item);
void RemoveAt(int index);
}
答案 0 :(得分:20)
ICollection<T>
在类型参数上不是协变的,而IEnumerable<T>
是。IEnumerable<T>
。如果您查看他们的声明(ICollection,IEnumerable),您会发现out
使用T
上的ICollection<T>
关键字,out
不
如果您考虑它,这是有道理的,因为(粗略地说)当界面仅用于读取对象(因此IEnumerable<T>
关键字)时,协方差是安全的。 ICollection<T>
明显符合这一标准,而IList<String> obj = new List<string>(); // Legal, of course
ICollection<Object> obj1 = obj; // Illegal, but let's see what happens
obj1.Add(new NonStringObject()); // That's not a string being stored in a List<string>
恰恰相反。
作为可能出错的一个例子(使用你的例子):
{{1}}
请记住:协方差与继承不同。仅仅因为两个类或接口共享一个继承关系并不意味着它们的类型参数共享相同的方差特征。
答案 1 :(得分:4)
这里的关键是集合是否可以修改。 IEnumerable<T>
是T
的只读集合,而ICollection<T>
支持Add
。可修改的集合不能协变,因为:
IList<String> obj = new List<String>();
ICollection<Object> obj1 = obj;
obj1.Add(new Elephant());
这将是类型检查,因为(推测)Elephant
是Object
的子类。但是现在obj
List<string>
有一个Elephant
作为最后一个元素,这显然是一件坏事。