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

P.B*_*key 9 .net c# polymorphism covariance

.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<in T>(T a);

        public interface IContainer<out T>
        {
            T GetItem();
            void Do(ContraAction<T> action);
        }

        public class Container<T> : IContainer<T>
        {
            private T item;

            public Container(T item)
            {
                this.item = item;
            }

            public T GetItem()
            {
                return item;
            }

            public void Do(ContraAction<T> 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<Shape> container = new Container<Circle>(circle);
            container.Do(s => s.Draw());//calls shape

            //Old school polymorphism...how is this not the same thing?
            Shape shape = new Circle();
            shape.Draw();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

JSB*_*ոգչ 10

考虑一个要求IContainer<Shape>:

public void DrawShape(IContainer<Shape> container>) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)

你有一个Container<Circle>.如何将容器传递给DrawShapeAPI?没有协方差,类型Container<Circle>不可转换为IContainer<Shape>,要求您重新包装类型或提出其他一些解决方法.

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


Ada*_*son 5

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

协方差和逆变(以及不变性和......无所不在......任何人?)处理泛型可以继承的"方向".在你的例子中,你正在做同样的事情,但这不是一个有意义的例子.

举个例子,事实IEnumerable<T>out T.这让我们做这样的事情:

public void PrintToString(IEnumerable<object> things)
{
    foreach(var obj in things)
    {
        Console.WriteLine(obj.ToString());
    }
}

public static void Main()
{
    List<string> strings = new List<string>() { "one", "two", "three" };
    List<MyClass> myClasses = new List<MyClass>();

    // add elements to myClasses

    PrintToString(strings);
    PrintToString(myClasses);
}
Run Code Online (Sandbox Code Playgroud)

在C#的早期版本中,这将是不可能的,因为List<string>工具IEnumerableIEnumerable<string>,没有 IEnumerable<object>.然而,因为IEnumerable<T>就是out T,我们知道,它现在转让或参数传递任何兼容的IEnumerable<Y>地方T is YT:Y.

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