虽然可以从基类/接口继承,但为什么不能声明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
    }
}

有别的办法吗?


当前回答

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

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

你也可以使用Linq:

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

其他回答

我个人喜欢创建带有类扩展的类库

public static List<TTo> Cast<TFrom, TTo>(List<TFrom> fromlist)
  where TFrom : class 
  where TTo : class
{
  return fromlist.ConvertAll(x => x as TTo);
}

因为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”。如何解释这一点呢?如果编译器真的想阻止我做一些愚蠢的事情,它应该阻止我做数组赋值。

至于为什么它不起作用,理解协方差和逆变可能会有所帮助。

只是为了说明为什么这不能工作,这里是对您提供的代码的更改:

void DoesThisWork()
{
     List<C> DerivedList = new List<C>();
     List<A> BaseList = DerivedList;
     BaseList.Add(new B());

     C FirstItem = DerivedList.First();
}

这可行吗?列表中的第一个项是类型“B”,但派生列表项的类型是C。

现在,假设我们真的只想创建一个泛型函数,它对实现了a的某个类型的列表进行操作,但我们不关心它是什么类型:

void ThisWorks<T>(List<T> GenericList) where T:A
{

}

void Test()
{
     ThisWorks(new List<B>());
     ThisWorks(new List<C>());
}

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

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

你也可以使用Linq:

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