为什么我不能这样做:
public Form1() {
IEnumerable<int> longEnum = new List<int>();
IEnumerable<object> objEnum = longEnum; // <-- Compiler error
}
......但我可以这样做吗?
public Form1() {
IEnumerable<Form1> formEnum = new List<Form1>();
IEnumerable<object> objEnum = formEnum;
}
我的猜测是,它与int
是结构的事实有关,而Form1
是一个类。
我有一个函数将返回IEnumerable<object>
,它的实际类型可能是更具体的,我在编译时不知道。即。
public interface IEnumFetcher{
IEnumerable<object> GetEnumeration{ get; }
}
public class EnumGetter1 : IEnumFetcher {
public IEnumerable<object> GetEnumeration() {
get { return new List<long>() ;} // <-- Doesn't compile
}
}
public class EnumGetter2 : IEnumFetcher {
public IEnumerable<object> GetEnumeration() {
get { return new List<string>() ;} // <-- Compiles just fine!
}
}
public class Form1{
public Form1(){
var getter1 = new EnumGetter1();
var getter2 = new EnumGetter2();
var getting1Result = getter1.GetEnumeration();
var getting2Result = getter2.GetEnumeration();
}
}
现在......更重要的问题是,我如何才能实现我想要做的事情?
答案 0 :(得分:1)
在C#中,方差仅适用于引用类型。来自Covariance and Contravariance FAQ:
仅当类型参数是引用类型时才支持差异。值类型不支持差异。
从C#Spec,13.1.3.2方差转换:
如果T是接口或委托,则类型
T<A1, …, An>
可以变量转换为类型T<B1, …, Bn>
使用变量类型参数T<X1, …, Xn>
声明的类型,并为每个变体类型参数Xi中的一个声明 以下是:
- Xi是协变的,从Ai到Bi
存在隐式参考或身份转换- Xi是逆变的,从Bi到Ai
存在隐式参考或身份转换- Xi是不变的,并且从Ai到Bi
存在身份转换
请注意,任何值类型与object
之间没有隐式引用或标识转换。只有拳击转换。
原因
问题是,如果编译器可以证明T<A>
可以与T<B>
完全相同的方式访问T<A>
,T<B>
只能转换为A
,而不必改变IL以使其有效。
如果B
或{{1}}是值类型,则两个泛型类型不可转换,因为编译器可能必须引入装箱/取消装箱指令。