请看以下示例(部分取自MSDN博客):
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)?
Jon*_*eet 112
那么这肯定不会在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就是你的朋友.
Lee*_*Lee 16
它将在C#4中工作IEnumerable<T>,所以你可以这样做:
IEnumerable<Animal> animals = new List<Giraffe>();
但是,List<T>这不是一个协变量投影,所以你不能像上面那样分配列表,因为你可以这样做:
List<Animal> animals = new List<Giraffe>();
animals.Add(new Monkey());
这显然无效.
就List<T>我而言,我担心你运气不好.但是,.NET 4.0/C#4.0增加了对协变/逆变接口的支持.具体来说,IEnumerable<T>现在定义为IEnumerable<out T>,这意味着类型参数现在是协变的.
这意味着您可以在C#4.0中执行类似的操作...
// implicit casting
IEnumerable<Animal> animalsList = new List<Giraffe>();
// explicit casting
IEnumerable<Animal> animalsList2 = (IEnumerable<Animal>) new List<Giraffe>();
注意:数组类型也是协变的(至少从.NET 1.1开始).
我认为很遗憾的是,没有添加方差支持IList<T>和其他类似的通用接口(或通用类甚至),但是哦,至少我们有一些东西.
其他人提到的可变集合不能支持协方差/逆变,因为在编译时不可能保证类型安全; 但是,如果您正在寻找的话,可以在C#3.5中进行快速单向转换:
List<Giraffe> giraffes = new List<Giraffe>();
List<Animal> animals = giraffes.Cast<Animal>().ToList();
当然它不是同一个东西,它实际上不是协方差 - 你实际上是在创建另一个列表,但它可以说是"解决方法".
在.NET 2.0中,您可以利用数组协方差来简化代码:
List<Giraffe> giraffes = new List<Giraffe>();
List<Animal> animals = new List<Animal>(giraffes.ToArray());
但请注意,您实际上是在这里创建两个新集合.
| 归档时间: | 
 | 
| 查看次数: | 15437 次 | 
| 最近记录: |