协变和逆变
Contents
协变和逆变
什么是协变和逆变
- 协变
- 因为 里氏替换原则 父类容器可以装子类对象
- 所以子类转换成父类 例如 string 转换成object
- 这样的转换 是协变 是和谐的转换
- 逆变
- 因为 里氏替换原则 父类容器可以装子类对象 但是子类容器不可以装父类对象
- 所以父类转换成子类 比如object转换成string
- 这样的转换 是逆变 是不和谐的
协变和逆变的用法
- 协变和逆变是用来修饰泛型的
- 使用关键字out(协变)和in(逆变)
- 用于在泛型中 修饰 泛型字母的
- 只有泛型接口和泛型委托中可以使用
out修饰的泛型 使其只能作为返回值
//T只能作为返回值
delegate T TestOut<out T>();
delegate T TestOut<out T>(T value);//报错
//在泛型接口中使用
interfacet Test<out T>{
T TestFun1();
void TestFun2(T value);//报错
}in修饰的泛型 使其只能作为参数
//T只能作为参数
delegate void TestIn<in T>(T value);
delegate T TestOIn<in T>(T value);//报错
//在泛型接口中使用
interfacet Test<in T>{
void TestFun2(T value);
T TestFun1();//报错
}通过里氏替换原则 理解协变
class Fater{}
class Son:Fater{}
delegate T TestOut<out T>();
delegate T TestNoOut<T>();
TestNoOut<Son> tnos = ()=>{return new Son();}
TestNoOut<Fater> tnof = tnos;//报错
//out修饰 会去判断父子关系
TestOut<Son> tos = ()=>{return new Son();}
TestOut<Fater> tof = tos;
//返回值为父类的方法 将子类作为返回值返回
//父类装子类 协变
Fater f = tof();
//返回值为子类的方法 不可以将父类作为返回值返回
tos = tof;//报错通过里氏替换原则 理解逆变
class Fater{}
class Son:Fater{}
delegate void TestIn<in T>(T value);
delegate void TestNoIn<T>(T value);
TestNoIn<Fater> tnif = (value)=>{};
TestNoIn<Son> tnis = tnif;//报错
//in修饰 会去判断父子关系
TestIn<Fater> tif = (value)=>{};
TestIn<Son> tis = tif;
//将子类的对象 传入了参数为父类的方法里
//子类转父类 逆变
tis(new sun());
//父类对象 不可以传入 子类作为参数的方法里
tif = tis;//报错协变和逆变有什么作用
- 协变(out)和逆变(in)是修饰 泛型的
- 协变 限定泛型只能作为 返回值
- 逆变 限定泛型只能作为 参数
- 协变:父类泛型委托容器 装 子类泛型泛型容器
- 返回值是子类的委托 加到 返回值是为父类的委托中
- 逆变:子类泛型泛型容器 装 父类泛型委托容器
- 参数是父类的委托 加到 参数为子类的委托中