协方差如何比多态更冷……而不是多余的?

.NET 4引入了协方差。 我想这很有用。 毕竟,MS经历了将其添加到C#语言的所有麻烦。 但是,为什么协方差比良好的旧多态更有用呢?

我写这个例子来理解为什么我应该实现Covariance,但我仍然没有得到它。 请赐教。

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Sample { class Demo { public delegate void ContraAction(T a); public interface IContainer { T GetItem(); void Do(ContraAction action); } public class Container : IContainer { private T item; public Container(T item) { this.item = item; } public T GetItem() { return item; } public void Do(ContraAction action) { action(item); } } public class Shape { public void Draw() { Console.WriteLine("Shape Drawn"); } } public class Circle:Shape { public void DrawCircle() { Console.WriteLine("Circle Drawn"); } } public static void Main() { Circle circle = new Circle(); IContainer container = new Container(circle); container.Do(s => s.Draw());//calls shape //Old school polymorphism...how is this not the same thing? Shape shape = new Circle(); shape.Draw(); } } } 

考虑一个要求IContainer的API:

 public void DrawShape(IContainer container>) { /* ... */ } 

你有一个Container 。 如何将容器传递给DrawShape API? 如果没有协方差, Container类型不能转换为IContainer ,要求您重新打包类型或提出其他一些解决方法。

在使用大量通用参数的API中,这不是一个罕见的问题。

协方差比多态性更冷,就像长耳兔比iceskates更冷:它们不是同一个东西。

协方差和逆变(以及不变性和……无所不在……任何人?)处理generics可以inheritance的“方向”。 在你的例子中,你正在做同样的事情,但这不是一个有意义的例子。

例如,考虑IEnumerable out T的事实。 这让我们做这样的事情:

 public void PrintToString(IEnumerable things) { foreach(var obj in things) { Console.WriteLine(obj.ToString()); } } public static void Main() { List strings = new List() { "one", "two", "three" }; List myClasses = new List(); // add elements to myClasses PrintToString(strings); PrintToString(myClasses); } 

在以前的C#版本中,这是不可能的,因为List实现IEnumerableIEnumerable而不是 IEnumerable 。 但是,由于IEnumerable out T ,我们知道它现在兼容任何IEnumerable赋值或参数传递,其中T is YT:Y

某些情况下,通过使函数本身具有通用性并使用generics类型推断,在许多情况下产生相同的语法,这种事情可以在以前的版本中解决。 然而,这并没有解决更大的问题,绝不是100%的解决方法。

这是generics版本:

 object[] arr = new string[5]; 

我会说它实际上是否需要是一个意见问题,因为它可能会引入类似于以下内容时发生的错误:

 arr[0] = new object(); //Run-time error 

但有时候它可以非常方便,因为它可以让你更好地重用代码。


编辑:

我忘记了 – 如果你正确使用它们,你可以通过使用outin关键字来防止这些错误。 所以没有太大的劣势。