Tom*_*duy 12 c# ienumerable covariance c#-4.0
C#4.0进一步扩展了通用类型和接口的协方差和逆变.有些接口(比如IEnumerable<T>)是协变量,所以我可以这样做:
IEnumerable<object> ie = new List<string>();
Run Code Online (Sandbox Code Playgroud)
但是这条线怎么样?我遇到了编译时错误
List<Object> list = new List<String>();
//Cannot implicitly convert type List<string>' to List<object>'
Run Code Online (Sandbox Code Playgroud)
我的意思是,如果List<T>实现IEnumerable<T>为什么List<T>仍然是不变的?有没有一个很好的反例可以解释为什么在C#中不允许这样做?
Jon*_*eet 21
首先,C#中的类总是不变的.你不能声明这样的类:
// Invalid
public class Foo<out T>
Run Code Online (Sandbox Code Playgroud)
其次 - 更重要的是你给出的例子 - List<T>无论如何都不能被声明为协变或逆变T,因为它有成员接受和返回类型的值T.
想象一下,如果它是协变的.然后你可以写这个(对于明显的Fruit类层次结构):
List<Banana> bunchOfBananas = new List<Banana>();
// This would be valid if List<T> were covariant in T
List<Fruit> fruitBowl = bunchOfBananas;
fruitBowl.Add(new Apple());
Banana banana = bunchOfBananas[0];
Run Code Online (Sandbox Code Playgroud)
你期望最后一行做什么?从根本上说,您不应该添加Apple对实际执行时类型为的对象的引用List<Banana>.如果你在一堆香蕉中加入一个苹果,就会掉下来.相信我,我试过了.
最后一行在类型方面应该是安全的 - a中的唯一值List<Banana>应该是null或引用实例Banana或子类.
现在至于为什么类不能协变,即使它们在逻辑上可以......我相信在实现级别引入问题,并且在编程级别也会非常严格.例如,考虑一下:
public class Foo<out T> // Imagine if this were valid
{
private T value;
public T Value { get { return value; } }
public Foo(T value)
{
this.value = value;
}
}
Run Code Online (Sandbox Code Playgroud)
这仍然可能必须是无效的 - 变量仍然是可写的,这意味着它被视为"in"插槽.你必须让每个类型的变量都是T只读的......那只是为了初学者.我强烈怀疑会有更深层次的问题.
就纯粹的实用主义而言,CLR支持v2-C#4的委托和接口差异,刚刚介绍了暴露该功能的语法.我不相信CLR曾经支持泛型类差异.
| 归档时间: |
|
| 查看次数: |
2869 次 |
| 最近记录: |