协方差如何比多态更冷……而不是多余的?
.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
在以前的C#版本中,这是不可能的,因为List
实现IEnumerable
和IEnumerable
, 而不是 IEnumerable
。 但是,由于IEnumerable
out T
,我们知道它现在兼容任何IEnumerable
赋值或参数传递,其中T is Y
或T:Y
。
在某些情况下,通过使函数本身具有通用性并使用generics类型推断,在许多情况下产生相同的语法,这种事情可以在以前的版本中解决。 然而,这并没有解决更大的问题,绝不是100%的解决方法。
这是generics版本:
object[] arr = new string[5];
我会说它实际上是否需要是一个意见问题,因为它可能会引入类似于以下内容时发生的错误:
arr[0] = new object(); //Run-time error
但有时候它可以非常方便,因为它可以让你更好地重用代码。
编辑:
我忘记了 – 如果你正确使用它们,你可以通过使用out
和in
关键字来防止这些错误。 所以没有太大的劣势。