Covariance and Contra-variance

Previous to .NET 4, generic interfaces were invariant. .NET 4 adds an important extension for generic
interfaces and generic delegates with covariance and contra-variance. Covariance and contra-variance
are about the conversion of types with argument and return types. For example, can you pass a
Rectangle to a method that requests a Shape? Let’s get into examples to see the advantages of these
extensions.
With .NET, parameter types are covariant. Assume you have the classes Shape and Rectangle, and
Rectangle derives from the Shape base class. The Display() method is declared to accept an object of the
Shape type as its parameter:
public void Display(Shape o) { }
Now you can pass any object that derives from the Shape base class. Because Rectangle derives
from Shape, a Rectangle fulfills all the requirements of a Shape and the compiler accepts this

method call:

Rectangle r = new Rectangle { Width= 5, Height=2.5};

Display(r);


Return types of methods are contra - variant. When a method returns a Shape it is not possible to assign it to
a Rectangle because a Shape is not necessarily always a Rectangle . The opposite is possible. If a method
returns a Rectangle as the GetRectangle() method,
public Rectangle GetRectangle();
the result can be assigned to a Shape .
Shape s = GetRectangle();
Before version 4 of the .NET Framework, this behavior was not possible with generics. With C# 4, the
language is extended to support covariance and contra - variance with generic interfaces and generic
delegates. Let ’ s start by defi ning a Shape base class and a Rectangle class:


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
{
}


Covariance with generic interfaces
A generic interface is covariant if the generic type is annotated with the out keyword. This also means that
type T is allowed only with return types. The interface IIndex is covariant with type T and returns this type
from a read - only indexer:
public interface IIndex < out T >
{
T this[int index] { get; }
int Count { get; }
}


The RectangleCollection.GetRectangles() method returns a RectangleCollection that implements
the IIndex<Rectangle> interface, so you can assign the return value to a variable rectangle of the
IIndex<Rectangle> type. Because the interface is covariant, it is also possible to assign the returned value
to a variable of IIndex<Shape>. Shape does not need anything more than a Rectangle has to offer. Using
the shapes variable, the indexer from the interface and the Count property are used within the for loop:
static void Main()
{
IIndex<Rectangle> rectangles = RectangleCollection.GetRectangles();
IIndex<Shape> shapes = rectangles;
for (int i = 0; i < shapes.Count; i++)
{
Console.WriteLine(shapes[i]);
}
}


Contra-Variance with generic interfaces
A generic interface is contra-variant if the generic type is annotated with the in keyword. This way the
interface is only allowed to use generic type T as input to its methods:

public interface IDisplay<in T>
{
void Show(T item);
}


The ShapeDisplay class implements IDisplay<Shape> and uses a Shape object as an input parameter:
public class ShapeDisplay: IDisplay<Shape>
{
public void Show(Shape s)
{
Console.WriteLine("{0} Width: {1}, Height: {2}", s.GetType().Name,
s.Width, s.Height);
}
}

Creating a new instance of ShapeDisplay returns IDisplay<Shape>, which is assigned to the
shapeDisplay variable. Because IDisplay<T> is contra-variant, it is possible to assign the result to
IDisplay<Rectangle> where Rectangle derives from Shape. This time the methods of the interface only
define the generic type as input, and Rectangle fulfills all the requirements of a Shape:
static void Main()
{
//...
IDisplay<Shape> shapeDisplay = new ShapeDisplay();
IDisplay<Rectangle> rectangleDisplay = shapeDisplay;
rectangleDisplay.Show(rectangles[0]);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值