2011-01-04 5 views
9

.NET 4は共分散を導入しています。私はそれが便利だと思います。結局のところ、MSはC#言語に追加する手間をすべて経ていました。しかし、なぜ共変は古き良き多形性よりも有用ですか?共分散は多型よりどのように涼しく...冗長ではないのですか?

私は共分散を実装すべき理由を理解するためにこの例を書いたが、それでもそれは得られない。私を教えてください。

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

あなたはこれを読んでください:http://stackoverflow.com/questions/1078423/c-is-variance-covariance-contravariance-another-word-for-polymorphism – rsenna

+0

あなたは本当に共分散について質問しているようですが、反共? –

+0

同意する、ダン。私は質問を編集するように誘惑されますが、私はブライアンが明確にするためにそれを残します。 –

答えて

10

IContainer<Shape>を要求するAPIを考えてみましょう:

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

あなたはContainer<Circle>を持っています。コンテナをDrawShape APIに渡すにはどうすればよいですか?共分散がない場合、タイプContainer<Circle>IContainer<Shape>に変換されません。タイプを再ラップするか、その他の回避策が必要です。

多くの一般的なパラメータを使用するAPIでこれは珍しい問題ではありません。

-1

それはのジェネリック版です:

:それはのようなことを言ったときに起こるもののようなバグを導入することができるので、私は、それが実際に必要なのかどうかは意見の問題だと思います

object[] arr = new string[5]; 

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

しかし、コードを再利用することができるので、とても便利なことがあります。


編集:

私は忘れてい - あなたがそれらを正しく使用している場合、outinキーワードを使用して、これらのバグを防ぐことができます。だから不利な点はあまりありません。

+0

実際には、反差異を追加する目的は、あなたが参照しているバグの種類を阻止することでした。 –

5

共分散は、ジャックビットがアイスケートよりも冷たいのと同じ方法で多型よりも冷たいです。それらは同じものではありません。

遺伝性は相続に関して行くことができる「方向」を共変および反動(および不変性および...全身...誰か)扱う。あなたの例では、同じことをしていますが、それは意味のある例ではありません。

例えば、IEnumerable<T>out Tであることを考慮してください。 List<string>IEnumerableIEnumerable<string>を実装としてのC#の以前のバージョンでは

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

、これは、不可能だったでしょう、ないIEnumerable<object>:これは私たちのこのような何かをすることができます。ただし、IEnumerable<T>out Tなので、の代入やパラメータの受け渡しに互換性があることがわかりました。T is YまたはT:Yです。

このようなことは、以前のバージョンでは、,の下で、関数そのものを汎用的にして、一般的な型の推論を使用して、多くの場合同じ構文を生成することによって回避することができました。しかし、これは大きな問題を解決するものではなく、決して100%の回避策ではありませんでした。

+0

しかし... jackrabbitsはiceskatesよりも涼しい! –

関連する問題