1. 程式人生 > >C#中協變與抗變(逆變)

C#中協變與抗變(逆變)

C#中協變與抗變(逆變)

在.NET 4之前,泛型介面是不變的,.NET4 通過協變 和抗變為泛型介面和泛型委託添加了一個重要的擴充套件。

協變和抗變指對引數和返回值的型別進行轉換

在.NET 中 引數型別是協變的;

也就是父類可以包含子類。

Cube 繼承於 Shape類;

pulic class Cube:Shape
{
    
}
public class Shape
{
public double width{get;set;}
public double heigth{get;set;}
}

public class Test
{
    static void Main()
{
      Cube  a=new  Cube();
        Shape b=new Shape();
            b=a;
        Display(a);
}

public static void Display(Shape o)
{
    //do something
}

}

 這裡 用父類作為引數, 因為 cube 派生自Shap類,,滿足Shap的所有要求,編譯器接受這個方法的呼叫,

而且父類可以作為容器 來儲存 子類;但本質上是子類不可以去儲存父類; 但是也可以強制轉換下讓編譯器去通過

  方法的返回型別是抗變的 

泛型型別用 out關鍵字 標註,泛型介面就是協變的。返回型別只能是T。 

public interface IIndex<out T>
{
    T this [int index]{get;}
    int Count{get;}
}

介面IIndex 和型別T的協變的,並從一個只讀索引器重返回這個型別

在 .NET4.0後 擴充套件的語言支援 泛型介面和泛型委託的協變和抗變.

不使用 in out標註,泛型就是不變的

 

泛型介面的抗變

如果泛型型別用in 關鍵字標註,泛型介面就是抗變的。這樣 介面只能把泛型型別T用作為其方法的輸入

 

  public interface IDisplay<in T>
    {
        void Show(T item);
    }
    public class ShapeDisplay : IDisplay<Shap>
    {
        public void Show(Shap shap) => Console.WriteLine($"{shap.GetType().Name} width:{shap.Width},height:{shap.Height}");
    }
   public static void Main()
    {
     // 6.42 泛型介面的協變;
        IIndex<Rectangle> rectangles = RectangleCollection.GetRectangles();

            IIndex<Shap> shapes = rectangles;
            for (int i = 0; i < shapes.Count; i++)
            {
                Console.WriteLine(shapes[i]);
            }
            Console.WriteLine(shapes[1]);
              //抗變;
          IDisplay<Shap> shapDisplay = new ShapeDisplay();

            IDisplay<Rectangle> rectangleDisplay = shapDisplay;
     //建立一個 ShapDisplay的新例項 會返回IDisplay<Shap> 並把它賦予shapeDisplay變數.
     //因為IDisplay<T>是抗變的。所以可以把結果 賦予IDisplay<Rectangle> ,Rectangle類繼承Shap類
     //這次介面的方法只能 把泛型型別定義為輸入,而Rectangle滿足Shape的所有要求
            rectangleDisplay.Show(rectangles[0]);
    }
public class RectangleCollection : IIndex<Rectangle>
    {
        private Rectangle[] data = new Rectangle[3]
        {
            new Rectangle{ Height=2,Width=5},

            new Rectangle{ Height=3,Width=7},

            new Rectangle{ Height=2,Width=5},
        };
        private static RectangleCollection _coll;
        public static RectangleCollection GetRectangles() => _coll ?? (_coll = new RectangleCollection());
        public Rectangle this[int index]
        {
            get
            {
                if (index < 0 || index > data.Length)
                    throw new ArgumentOutOfRangeException("index");
                return data[index];
            }
        }
        public int Count => data.Length;

    }