分配/强制转换更特定类型的IEnumerable<;对象>;不使用structs

本文关键字:对象 lt gt structs IEnumerable 转换 类型 分配 | 更新日期: 2023-09-27 18:14:01

为什么我不能这样做:

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();
    }
}

现在。。。更重要的问题是,我如何才能实现我想要做的事情

分配/强制转换更特定类型的IEnumerable<;对象>;不使用structs

在C#中,方差只适用于引用类型。来自协方差和方差常见问题解答:

只有当类型参数是引用类型时,才支持差异。值类型不支持差异。

根据C#规范,13.1.3.2方差转换:

如果T是接口或委托,则类型T<A1, …, An>可变化为类型T<B1, …, Bn>用变量类型参数T<X1, …, Xn>声明的类型,并且对于每个变量类型参数Xi以下保持:

  • Xi是协变的,存在从Ai到Bi的隐式引用或同一性转换
  • Xi是反变的,存在从Bi到Ai的隐式引用或身份转换
  • Xi是不变的,存在从艾到毕的同一性转换

请注意,在任何值类型和object之间都不存在隐式引用或身份转换。只有拳击转换。

原因

问题是,只有当编译器能够证明T<A>可以以与T<B>完全相同的方式访问,而不必更改IL使其工作时,T<A>才能转换为T<B>

如果AB是值类型,那么这两个泛型类型是不可转换的,因为编译器可能必须引入装箱/取消装箱指令。