虽然可以从基类/接口继承,但为什么不能声明List<>呢 使用相同的类/接口?

interface A
{ }

class B : A
{ }

class C : B
{ }

class Test
{
    static void Main(string[] args)
    {
        A a = new C(); // OK
        List<A> listOfA = new List<C>(); // compiler Error
    }
}

有别的办法吗?


当前回答

因为c#目前不允许这种类型的继承转换。

其他回答

实现这种工作的方法是遍历列表并强制转换元素。这可以使用ConvertAll:

List<A> listOfA = new List<C>().ConvertAll(x => (A)x);

你也可以使用Linq:

List<A> listOfA = new List<C>().Cast<A>().ToList();

因为c#目前不允许这种类型的继承转换。

我已经阅读了整篇文章,我只是想指出对我来说似乎不一致的地方。

编译器阻止你对list执行赋值操作:

List<Tiger> myTigersList = new List<Tiger>() { new Tiger(), new Tiger(), new Tiger() };
List<Animal> myAnimalsList = myTigersList;    // Compiler error

但是编译器完全可以处理数组:

Tiger[] myTigersArray = new Tiger[3] { new Tiger(), new Tiger(), new Tiger() };
Animal[] myAnimalsArray = myTigersArray;    // No problem

关于任务是否安全的争论在这里站不住脚了。我对数组的赋值是不安全的。为了证明这一点,如果我继续这样做:

myAnimalsArray[1] = new Giraffe();

我得到一个运行时异常“ArrayTypeMismatchException”。如何解释这一点呢?如果编译器真的想阻止我做一些愚蠢的事情,它应该阻止我做数组赋值。

你也可以使用System.Runtime.CompilerServices.Unsafe NuGet包来创建同一个列表的引用:

using System.Runtime.CompilerServices;
...
class Tool { }
class Hammer : Tool { }
...
var hammers = new List<Hammer>();
...
var tools = Unsafe.As<List<Tool>>(hammers);

对于上面的示例,您可以使用tools变量访问列表中现有的Hammer实例。将Tool实例添加到列表中会抛出ArrayTypeMismatchException异常,因为tools引用了与hammers相同的变量。

首先,停止使用难以理解的类名,如A, B, c,使用动物,哺乳动物,长颈鹿,或食物,水果,橙子或其他关系清楚的东西。

你的问题是"既然我可以把长颈鹿赋值给动物类型的变量,为什么我不能把长颈鹿的列表赋值给动物类型的变量?"

答案是:假设你可以。那么会出什么问题呢?

嗯,你可以在动物列表中添加一只老虎。假设我们允许您将一个长颈鹿列表放入一个包含动物列表的变量中。然后你试着在名单上加上一只老虎。会发生什么呢?你想在长颈鹿的名单中包含一只老虎吗?你想撞车吗?或者你希望编译器通过在第一时间使赋值非法来保护你不崩溃?

我们选择后者。

这种转换称为“协变”转换。在c# 4中,我们将允许您在接口和委托上进行协变转换,前提是这种转换总是安全的。详见我关于协方差和逆变的博客文章。(这周的周一和周四会有一个新的话题。)