开发者

How is covariance cooler than polymorphism...and not redundant?

.NET 4 introduces covariance. I guess it is useful. After all, MS went through all the trouble of adding it to the C# language. But, why is Covariance more useful than good old polymorphism?

I wrote this example to understand why I should implement Covariance, but I still don't get it. Please enlighten me.

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);
    开发者_StackOverflow中文版        }
        }

        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();
        }
    }
}


Consider an API which asks for an IContainer<Shape>:

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

You have a Container<Circle>. How can you pass your container to the DrawShape API? Without covariance, the type Container<Circle> is not convertible to IContainer<Shape>, requiring you to rewrap the type or come up with some other workaround.

This is not an uncommon problem in APIs that use a lot of generic parameters.


Covariance is cooler than polymorphism in the same way that jackrabbits are cooler than iceskates: they're not the same thing.

Covariance and contravariance (and invariance and...omnivariance...anybody?) deal with the "direction" that generics can go with regard to inheritance. In your example, you're doing the same thing, but that's not a meaningful example.

Consider, for example, the fact that IEnumerable<T> is out T. This lets us do something like this:

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);
}

In previous versions of C#, this would have been impossible, as List<string> implements IEnumerable and IEnumerable<string>, not IEnumerable<object>. However, since IEnumerable<T> is out T, we know that it's now compatible for assignment or parameter passing for any IEnumerable<Y> where T is Y or T:Y.

This sort of thing could be worked around in previous versions under some circumstances by making the function itself generic and using generic type inference, yielding identical syntax in many cases. This, however, did not solve the larger problem and was by no means a 100% workaround.


It's the generics version of:

object[] arr = new string[5];

I'd say whether or not it's actually needed is a matter of opinion, since it can introduce bugs like those that happen when saying things like:

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

But sometimes it can be very handy, since it lets you re-use code better.


Edit:

I'd forgotten -- you can prevent those bugs by using the out and in keywords, if you use them correctly. So there's not much of a disadvantage.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜