在.NET4.0中,新加入了协变与抗变的内容,最近查了一下MSDN,对它有了一个大概的理解,希望能够帮助到和我一样的菜鸟。
协变:
协变非常类似于普通的多态性的分配,它是针对成员的返回值类型,定义时使用关键字out,假定您有一个名为 Base 的基类和一个名为 Derived 的派生类:
IEnumerable<Derived> d = new List<Derived>();
IEnumerable<Base> b = d;
这就是一个简单的协变的应用,它主要是从派生类到基类的一个转化。
抗变(逆变):
抗变主要是在传递类型参数的时候使用的,定义时使用关键字in,这样做有利于保证参数传递的安全性和效率。还是上边的例子:
IDisplay<Base> bd=new ShapeDisplay();
IDisplay<Derived> dd=bd;
这是一个简单的抗变的例子,它主要是从基类到派生类的转换。
下边是一个协变抗变综合在一块的例子:
using System;
using System.Collections;
using System.Collections.Generic;
namespace xiebian
{
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
{
}
public interface IIndex<out T>
{
T this[int index]{get;}
int Count{get;}
}
public class RectangleCollection:IIndex<Rectangle>
{
private Rectangle[] data=new Rectangle[3]
{
new Rectangle{Height=1,Width=5},
new Rectangle{Height=2,Width=6},
new Rectangle{Height=5,Width=7}
};
public static RectangleCollection GetRectangles()
{
return new RectangleCollection();
}
public Rectangle this[int index]
{
get
{
if(index<0||index>data.Length)
throw new ArgumentOutOfRangeException("index");
return data[index];
}
}
public int Count
{
get
{
return data.Length;
}
}
}
public interface IDisplay<in T>
{
void Show(T item);
}
public class ShapeDisplay:IDisplay<Shape>
{
public void Show(Shape s)
{
Console.WriteLine("{0} Width:{1} ,Height:{2}",s.GetType().Name,s.Width,s.Height);
}
}
class Program
{
public static void Main()
{
IIndex<Rectangle> rectangles=RectangleCollection.GetRectangles();
IIndex<Shape> shapes=rectangles;
//这里用的是协变,它是针对成员的返回值类型,从派生类到基类的转换。
for(int i=0;i<shapes.Count;i++)
Console.WriteLine(shapes[i]);
IDisplay<Shape> shapedisplay=new ShapeDisplay();
IDisplay<Rectangle> rectangledisplay=shapedisplay;
//这里用的是抗变,它是针对传递的参数类型,从基类到派生类的转换。
//当然,前提是保证程序能够正常的运行,即:IDisplay(Shape s)not IDisplay(Rectangle s)(需要的是基类即可完成的任务)
rectangledisplay.Show(rectangles[0]);
}
}
}
结果: