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
{
    T this [int index]{get;}
    int Count{get;}
}

接口IIndex 和类型T的协变的,并从一个只读索引器重返回这个类型

在 .NET4.0后 扩展的语言支持 泛型接口和泛型委托的协变和抗变.

不使用 in out标注,泛型就是不变的

 

泛型接口的抗变

如果泛型类型用in 关键字标注,泛型接口就是抗变的。这样 接口只能把泛型类型T用作为其方法的输入

 

  public interface IDisplay
    {
        void Show(T item);
    }
    public class ShapeDisplay : IDisplay
    {
        public void Show(Shap shap) => Console.WriteLine($"{shap.GetType().Name} width:{shap.Width},height:{shap.Height}");
    }
   public static void Main()
    {
     // 6.42 泛型接口的协变;
        IIndex rectangles = RectangleCollection.GetRectangles();

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

            IDisplay rectangleDisplay = shapDisplay;
     //创建一个 ShapDisplay的新实例 会返回IDisplay 并把它赋予shapeDisplay变量.
     //因为IDisplay是抗变的。所以可以把结果 赋予IDisplay ,Rectangle类继承Shap类
     //这次接口的方法只能 把泛型类型定义为输入,而Rectangle满足Shape的所有要求
            rectangleDisplay.Show(rectangles[0]);
    }
public class RectangleCollection : IIndex
    {
        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;

    }

 

你可能感兴趣的:(C#)