具有派生泛型类型的列表的奇怪行为

本文关键字:列表 派生 泛型类型 | 更新日期: 2023-09-27 18:06:43

所以我有一个基类型的列表。这个基类型有两个派生类,其中一个是泛型的。我试着逐一浏览列表,发现了这个奇怪的行为。

public static void Test<T>()
{
    List<Base> myList = new List<Base>();
    myList.Add(new aDerived());
    myList.Add(new tDerived<T>());
    foreach (tDerived<T> lGen in myList as List<tDerived<T>>)
    {
        // This is fine
    }
    foreach (aDerived lDerived in myList as List<aDerived>)
    {
        // Error: Can't convert... via a reference conversion etc 
    }
}
//Simple classes to repro:
class Base
{
}
class aDerived : Base
{
}
class tDerived<T> : Base
{
}

此报告错误CS0039如果指定了类型,即我将T替换为int而不是参数方法,那么我在第一个循环中也会得到相同的错误。

问题:为什么会这样?我看不出任何本质上不可能的事情,毕竟,我可以在每次迭代的返回类型上执行as。另一方面,如果这个东西是模板类,为什么它能工作呢?这似乎不能帮助它工作。

具有派生泛型类型的列表的奇怪行为

以下操作均不能进行。不确定,但只要编译器知道aDerived类型,它就会告诉您不能这样做(编译时错误)。但在第二种情况下,编译器没有足够的信息关于tDerived<T>的确切类型(因为它将在运行时指定-因为你的方法是一个泛型方法),所以它不会通知你。但是当运行代码时,它会抛出异常。

var result1 = myList as List<aDerived>;     //Compile-time error
var result2 = myList as List<tDerived<T>>   //null

更有趣的:这可以在没有编译时错误的情况下完成:

List<Base> myList = new List<Base>();
var result = myList as List<T>;             //No Compile-time error

这个链接也可能是有用的:协方差和逆变。

这个问题是您正在尝试将derived和tDerived的列表转换为其中一个或另一个。这是行不通的,因为它就像试图将水果列表(香蕉和苹果)转换成苹果列表一样。但是,您可以做的是使用OfType扩展来遍历正确类型的项:

foreach (tDerived<T> lGen in myList.OfType<tDerived<T>>())
{
    Console.WriteLine("tDerived found!");
}
foreach (aDerived lDerived in myList.OfType<aDerived>())
{
    Console.WriteLine("aDerived found!");
}

MSDN OfType: http://msdn.microsoft.com/en-us/library/bb360913(v=vs.100).aspx