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());