协变和逆变是用来修饰泛型字母的,只用在泛型接口和泛型委托中
协变:out ○ 父类装子类
逆变:in ○ 子类装父类
作用:
1. 委托类型
a. in 修饰的泛型字母,只能作参数
b. out 修饰的泛型字母,只能作返回值
2. 委托变量
a. 由有out修饰的委托定义的两个不同类型的委托变量,互相赋值时会自动判断返回值之间是否存在继承关系。
b.由有in修饰的委托定义的两个不同类型的委托变量,互相赋值时会自动判断对应参数之间是否存在继承关系。
using System;
namespace 协变逆变_委托
{
// ----------------修饰委托-----------------------------
delegate T Func1<T> ();
delegate void Func2<T> (T t);
delegate T Func_Out<out T> ();
delegate void Func_In<in T> (T t);
// delegate T Func0<in T> (); //报错 “T”为 逆变。
// delegate T Func0<out T> (T t); //报错 “T”为 协变。
class Father
{
}
class Son : Father
{
}
class Program
{
static void Main (string[] args)
{
// --------------协变----------------------------------
//Func1<Son> funcSon = () => new Son();
//Func1<Father> funcFather = funcSon;
//报错: 无法将Func<Son>隐式转换为Func<Father>
// 因为funcSon 和 funcFather 为同级的委托。
Func_Out<Son> outSon = () => new Son();
Func_Out<Father> outFather = outSon;
// 编译通过:加了out后会自动判断返回类型有无继承关系。 (父类装了子类)
// 从表现上来看,像是父类泛型委托装了子类泛型委托,是和谐的(协变)
Father father = outFather(); // 返回值为Son转换成的Father类型 (父类装了子类)
//Son son = outFather(); 报错 因为返回类型以及是Father了, 子类不能装父类
// --------------逆变----------------------------------
//Func2<Father> funcFather = (value) => { };
//Func2<Son> funcSon = funcFather;
// 报错 : 无法将Func<Father>隐式转换为Func<Son> 因为funcSon 和 funcFather 为同级的委托。
Func_In<Father> inFather = (value) => { };
Func_In<Son> inSon = inFather;
// 编译通过:加了 in 后会自动判断参数类型有无继承关系。 (父类装了子类)
inSon(new Son());
//inSon(new Father()); 报错
// 从表现上来看,像是子类泛型委托装了父类泛型委托,是不和谐的(逆变)
}
}
}