一尘不染

C#方差问题:分配列表 作为列表

c#

看下面的示例(部分取自MSDN
Blog
):

class Animal { }
class Giraffe : Animal { }

static void Main(string[] args)
{
    // Array assignment works, but...
    Animal[] animals = new Giraffe[10];

    // implicit...
    List<Animal> animalsList = new List<Giraffe>();

    // ...and explicit casting fails
    List<Animal> animalsList2 = (List<Animal>) new List<Giraffe>();
}

这是一个协方差问题吗?将来的C#版本中是否会支持此方法,并且有任何巧妙的解决方法(仅使用.NET 2.0)吗?


阅读 261

收藏
2020-05-19

共1个答案

一尘不染

好吧,这当然在C#4中将不受支持。存在一个基本问题:

List<Giraffe> giraffes = new List<Giraffe>();
giraffes.Add(new Giraffe());
List<Animal> animals = giraffes;
animals.Add(new Lion()); // Aargh!

保持长颈鹿的安全:对不安全的差异说不。

数组版本之所以起作用,是因为数组 确实 支持引用类型差异以及执行时间检查。泛型的重点是提供 编译时 类型的安全性。

在C#4中,将支持 安全的 通用变量,但仅支持接口和委托。这样您就可以执行以下操作:

Func<string> stringFactory = () => "always return this string";
Func<object> objectFactory = stringFactory; // Safe, allowed in C# 4

Func<out T>协变的T因为T仅用于输出位置。比较与之Action<in T>相反的T原因,因为T它仅在此处的输入位置使用,因此很安全:

Action<object> objectAction = x => Console.WriteLine(x.GetHashCode());
Action<string> stringAction = objectAction; // Safe, allowed in C# 4

IEnumerable<out T> 也是协变的,这在C#4中是正确的,正如其他人指出的那样:

IEnumerable<Animal> animals = new List<Giraffe>();
// Can't add a Lion to animals, as `IEnumerable<out T>` is a read-only interface.

关于在C#2中解决此问题的方式,您是否需要维护 一个 列表,还是愿意创建一个新列表?如果可以接受,List<T>.ConvertAll是您的朋友。

2020-05-19