今天简单说说.net 4.0里面的新特性:变体
我们知道可以用父类对象指向子类引用,我写两个简单的类。
- public abstract class Shape
- {
- public float Width { get; set; }
- public float Height { get; set; }
- public abstract float GetPerimeter();
- public abstract float GetArea();
- }
public abstract class Shape
{
public float Width { get; set; }
public float Height { get; set; }
public abstract float GetPerimeter();
public abstract float GetArea();
}
- public class Rectangle : Shape
- {
- public Rectangle(float width, float height)
- {
- this.Width = width;
- this.Height = height;
- }
- public override float GetPerimeter()
- {
- return 2 * (Width + Height);
- }
- public override float GetArea()
- {
- return Width * Height;
- }
- }
public class Rectangle : Shape
{
public Rectangle(float width, float height)
{
this.Width = width;
this.Height = height;
}
public override float GetPerimeter()
{
return 2 * (Width + Height);
}
public override float GetArea()
{
return Width * Height;
}
}
那么我们可以用如下代码实例化Rectangle类:
- Shape sh = new Rectangle(3, 4);
Shape sh = new Rectangle(3, 4);
当然这也是实现多态性的前提条件,但是这个却不适用于泛型,比如无法用如下代码实例化List<Rectangle>类:
- List<Shape> shs = new List<Rectangle>();
List<Shape> shs = new List<Rectangle>();
不过有了变体之后我们便可以实现这种代码了,变体分为两种:协变 和 抗变
1、协变
协变用out关键字声明,比如GenericClass<out T>,协变中,T类型只能用作输出参数,并且允许在泛型中用父类指向子类引用。
2、抗变
抗变用in关键字声明,比如GenericClass<in T>,抗变中,T类型只能用作输入参数,不过抗变有点奇怪,抗变允许在泛型中用子类指向父类引用。
我下面用一个例子来简单描述一下变体。
先扩充一个类:
- public class RichRectangle : Rectangle
- {
- public int BorderWidth { get; set; }
- public Color BorderColor { get; set; }
- public Color BackColor { get; set; }
- public RichRectangle(float width, float height)
- : this(width, height, 1, Color.Black, Color.White)
- { }
- public RichRectangle(float width, float height, int bdrWidth, Color bdrColor, Color bgColor)
- : base(width, height)
- {
- this.BorderWidth = bdrWidth;
- this.BorderColor = bdrColor;
- this.BackColor = bgColor;
- }
- }
public class RichRectangle : Rectangle
{
public int BorderWidth { get; set; }
public Color BorderColor { get; set; }
public Color BackColor { get; set; }
public RichRectangle(float width, float height)
: this(width, height, 1, Color.Black, Color.White)
{ }
public RichRectangle(float width, float height, int bdrWidth, Color bdrColor, Color bgColor)
: base(width, height)
{
this.BorderWidth = bdrWidth;
this.BorderColor = bdrColor;
this.BackColor = bgColor;
}
}
定义IIndex和IAppend接口和一个RectangleCollection类
- public interface IIndex<out T>
- {
- T this[int index] { get; }
- int Count { get; }
- }
public interface IIndex<out T>
{
T this[int index] { get; }
int Count { get; }
}
- public interface IAppend<in T>
- {
- void Add(T item);
- void Insert(int index, T item);
- }
public interface IAppend<in T>
{
void Add(T item);
void Insert(int index, T item);
}
- public class RectangleCollection : IIndex<Rectangle>, IAppend<Rectangle>, IEnumerable<Rectangle>
- {
- private List<Rectangle> rects;
- public RectangleCollection()
- {
- this.rects = new List<Rectangle>();
- }
- public Rectangle this[int index]
- {
- get { return rects[index]; }
- }
- public int Count
- {
- get { return rects.Count; }
- }
- public void Add(Rectangle item)
- {
- this.rects.Add(item);
- }
- public void Insert(int index, Rectangle item)
- {
- this.rects.Insert(index, item);
- }
- public IEnumerator<Rectangle> GetEnumerator()
- {
- return this.rects.GetEnumerator();
- }
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
- }
public class RectangleCollection : IIndex<Rectangle>, IAppend<Rectangle>, IEnumerable<Rectangle>
{
private List<Rectangle> rects;
public RectangleCollection()
{
this.rects = new List<Rectangle>();
}
public Rectangle this[int index]
{
get { return rects[index]; }
}
public int Count
{
get { return rects.Count; }
}
public void Add(Rectangle item)
{
this.rects.Add(item);
}
public void Insert(int index, Rectangle item)
{
this.rects.Insert(index, item);
}
public IEnumerator<Rectangle> GetEnumerator()
{
return this.rects.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
IIndex<T>是协变的泛型接口、IAppend<T>是抗变的泛型接口,写一个测试类:
- class Program
- {
- static void Main(string[] args)
- {
- var rects = new RectangleCollection();
- var rect1 = new Rectangle(3, 4);
- var rect2 = new Rectangle(7, 4);
- var rect3 = new Rectangle(4, 8);
- rects.Add(rect1);
- rects.Add(rect2);
- rects.Add(rect3);
- IIndex<Shape> shapes = rects;//这里由于IIndex是协变,因此可以指向实现了IIndex<Rectangle>的RectangleCollection类
- IAppend<RichRectangle> richRects = rects;//同理,这里是逆变,可以指向父类
- richRects.Add(new RichRectangle(5, 5));
- foreach (var rect in rects)
- {
- Console.WriteLine(rect.GetPerimeter() + ", " + rect.GetArea());
- }
- Console.ReadKey();
- }
- }
class Program
{
static void Main(string[] args)
{
var rects = new RectangleCollection();
var rect1 = new Rectangle(3, 4);
var rect2 = new Rectangle(7, 4);
var rect3 = new Rectangle(4, 8);
rects.Add(rect1);
rects.Add(rect2);
rects.Add(rect3);
IIndex<Shape> shapes = rects;//这里由于IIndex是协变,因此可以指向实现了IIndex<Rectangle>的RectangleCollection类
IAppend<RichRectangle> richRects = rects;//同理,这里是逆变,可以指向父类
richRects.Add(new RichRectangle(5, 5));
foreach (var rect in rects)
{
Console.WriteLine(rect.GetPerimeter() + ", " + rect.GetArea());
}
Console.ReadKey();
}
}
转自:http://blog.youkuaiyun.com/wanxindavid/article/details/8525378