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

时间:2013-03-30 18:47:48

标签: c# generics

所以我有一个基本类型列表。此基类型有两个派生类,其中一个是通用的。我试图通过列表进行预测,发现了这种奇怪的行为。

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。另一方面,如果事物是​​模板类,它为什么会起作用,似乎不应该帮助它起作用。

2 个答案:

答案 0 :(得分:2)

以下操作均无法完成。不确定,但只要编译器知道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

此链接也可能有用:Covariance and Contravariance

答案 1 :(得分:1)

此问题是您尝试将aDerived和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