C#种的协变和逆变只能针对泛型的接口和委托。在C#1的时候委托是撑持参数的协变和逆变的。
协变和逆变素质上是针对类型和类型之间的绑定的。好比说数组,数组其实就是一种和具体类型之间产生绑定的类型。数组类型Int32[]就对应于Int32这个原本的类型。任何类型T都有其对应的数组类型T[]。我们说:如果有类型Parent和其子类Sub,那么Parent p=new Sub();这种的类型转换是安适的。如果有一种类型和Parent类型进行了绑定,好比说Parent[]数组,如果Sub[]到Parent[]的转换是安适的,我们就说是协变,如果相反的标的目的上转换是安适的,我们就说是逆变了。C#中我们知道数组是协变的,也就是说Sub[]到Parent[]的转换是安适的。再举个例子,就是String类型担任自Object类型,所以任何String的引用都可以安适地转换为Object引用。我们发明String[]数组类型的引用也担任了这种转换能力,它可以转换成Object[]数组类型的引用,数组这种与原始类型转换标的目的不异的可变性就称作协变(covariant)。
由于数组不撑持反变性,我们无法用数组的例子来解释反变性,所以我们此刻就来看看泛型接口和泛型委托的可变性。假设有这样两个类型:TSub是TParent的子类,显然TSub型引用是可以安适转换为TParent型引用的。如果一个泛型接口IFoo<T>,IFoo<TSub>可以转换为IFoo<TParent>的话,我们称这个过程为协变,而且说这个泛型接口撑持对T的协变。而如果一个泛型接口IBar<T>,IBar<TParent>可以转换为T<TSub>的话,我们称这个过程为反变(contravariant),而且说这个接口撑持对T的反变。因此很好理解,如果一个可变性和子类到父类转换的标的目的一样,就称作协变;而如果和子类到父类的转换标的目的相反,就叫反变性。
,