接口和委托的泛型可变性

Before You Read:

This article is ablout a branch of generic. Covariant and Contravariant. Generic first come up in C#2.0,in that time period. Generic variance is not support. It called invariant.

Where should we use conravariant?

​ We can transform SomeType<Circle> to SomeType<IShape> when we use covariant. However, contravariant is opposite. It can transform SomeType<IShape to SomeType<Circle>.

Only when SomeType describe return type parameter, covariant is safe.

Only when SomeType describe accept type parameter, contravariant is safe.

协变性和逆变性

可变性是以一种类型安全的方式,将一个对象作为另一个对象来使用。例如:若某方法声明返回类型为 Stream ,在实现时可以返回一个 MemoryStream。可变性应用于泛型接口和泛型委托的类型参数中。

协变性

​ 协变性用于向调用者返回某项操作的值。

interface IFactory<T>
  {
    T CreateFactoryInstance();
  }

上述 T 仅作为返回值使用, 即方法的输出。

逆变性

​ 逆变性指的是调用者向API传人值,API是在使用值,而不是产生值。

interface IPrinter<T>
  {
    void Print(T document);
  }

上述 T 只作为参数出现在接口的输入位置。

还有一个就是 不变性, 这种类型称为 不变体 (invariant)

在接口中使用可变性

​ 在泛型接口或委托的声明中,使用 out 修饰符来制定类型参数的 协变性, 使用 in 修饰符来指定 逆变性

: 变体的转换是引用转换 任何使用了协变和逆变的转换都是引用转换,这意味着转换之后将返回相同的引用。它不会创建新的对象,只是认为现有引用与目标类型匹配。

使用in 和out 表示可变性

//Interface Example
public interface IEnumerbale<out T>
public interface IComparer<in T>

如果类型参数只用于输出,就使用out; 如果只用于输入,就用in

//A Demo for interface convarint

List<Circle> aCircle = new List<Circle>
  {
      new Circle(new Point(0,0),15),
      new Circle(new Point(1,1),10)
  };

List<Trangle> aTrangle = new List<Trangle>
  {
      new Trangle(new Point(1,1),2),
      new Trangle(new Point(2,2),3)
  };

接口的协变性

List<IShape> shapes = new List<IShape>();
shapes.AddRange(aCircle);
shapes.AddRange(aTrangle);

List<IShape> shapesAll = aCircle.Contact<IShape>(aTrangle).ToList();

接口的逆变性

class AreaComparer : IComparer<IShape>
  {
    public int Compare(IShape x, IShape y){
      return x.Area.CompareTo(y.area);
    }
  }

在委托中使用可变性

delegate T Func<out T>()
delegate void Action<in T>(T obj)
//使用Func<T> 和 Action<T>委托演示可变性
Func<Trangle> TrangleFactory = () => new Trangle(new Point(1,1),2);
Func<IShape> shapeFactory = TrangleFactory;

Action<IShape> shapePrinter = shape => Console.WriteLine(shape.area);
Action<Trangle> TranglePrinter = shapePrinter;

shapePrinter(shapeFactory());
TranglePrinter(TrangleFactory());
posted @ 2017-08-06 21:05  BUTTERAPPLE  阅读(326)  评论(0编辑  收藏  举报