所以我有一个基本类型列表。此基类型有两个派生类,其中一个是通用的。我试图通过列表进行预测,发现了这种奇怪的行为。
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
。另一方面,如果事物是模板类,它为什么会起作用,似乎不应该帮助它起作用。
答案 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