在.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;
}