C# 协变与抗变
之前在编写程序的过程中,遇到了这个概念。
在.NET 4之前,泛型接口是不变的。.NET 4通过协变和抗变为泛型接口和泛型委托添加了一个重要的扩展。协变和抗变指对参数和返回值的类型进行转换。例如,可以给一个需要Shape参数的方法传送Rectangle参数码?下面用示例说明这些扩展的优点。
在.NET中,参数类型是协变的。假定有Shape和Rectangle类,Rectangle派生自Shape基类。声明Display()方法是为了接受Shape类型的对象作为其参数:
public void Display(Shape o) { } //形参是基类,实参是派生类 这是协变 ,就是说本来预想要个 10 结果人家给了个100,当然可以接受了-。-
现在可以传递派生自Shape基类的任意对象。因为Rectangle派生自Shape,所以Rectangle满足Shape的所有要求,编译器接受这个方法调用:
Rectangle r = new Rectangle { Width= 5, Height=2.5};
Display(r);
方法的返回类型是抗变的。当方法返回一个Shape时,不能把它赋予Rectangle,因为Shape不一定总是Rectangle。反过来是可行的:如果一个方法像GetRectangle()方法那样返回一个Rectangle,
public Rectangle GetRectangle(); //返回值类型是派生类,结果返回的是基类,可以 就是说 我可以给出100,结果你只需要10,当然可以 反过来就不行了
就可以把结果赋予某个Shape:
Shape s = GetRectangle();
在.NET Framework 4版本之前,这种行为方式不适用于泛型。在C# 4中,扩展后的语言支持泛型接口和泛型委托的协变和抗变。下面开始定义Shape基类和Rectangle类:
public class Shape
{
public double Width { get; set; }
public double Height { get; set; }
public override string ToString()
{
return String.Format("Width: {0}, Height: {1}", Width, Height);
}
}
public class Rectangle: Shape
{
}