那些年搞不懂的术语、概念:协变、逆变、不变体
简述什么是协变性、逆变性、不变性协变性如string-object 子类到父类的转换逆变性如object-string 父类到子类的转换不变性基于上面两种情况不可变。具体下面再做分析。泛型委托的可变性先使用框架定义的泛型委托Func和Action做例子不了解的请戳协变(string-object)Funcstring func1 () 农码一生; Funcobject func2 func1;逆变(object-string)Actionobject func3 t { }; Actionstring func4 func3;上面代码没有任何问题。接着我们自己定义委托试试我X看人不来哦。为什么自定义的委托却不能协变呢。我看看系统定义的Func到底和我们自定义的有什么不同public delegate TResult Funcout TResult();多了一个out什么鬼:out对于泛型类型参数out 关键字指定该类型参数是协变的。 可以在泛型接口和委托中使用 out 关键字。来源in对于泛型类型参数in 关键字指定该类型参数是逆变的。 可以在泛型接口和委托中使用 in 关键字。来源那么我们可以修改自定义委托完美那如果我们要实现逆变性呢直接逆变是不可行的我们需要修改泛型类型参数我们发现整个委托参数都变了。本来的返回值改成输入参数才行。结论in-输入参数-可逆变父类到子类的转变[如 object-string]out-返回值-可协变子类到父类的转变[如 string-object]假设如果泛型参数中既存在in又存在out改如何delegate Tout MyFuncin Tin, out Tout(Tin obj);MyFuncobject, string str1 t 农码一生; MyFuncstring, string str2 str1;//第一个泛型的逆变object-string MyFuncobject, object str3 str1;//第二个泛型的协变string-object MyFuncstring, object str4 str1;//第一个泛型的逆变和第二个泛型的协变以上都是没有问题的。然后我们看看编译后的C#代码结论所谓的逆变其实只是编译后进行了强制类型转换而已。以上代码也可以直接写成//delegate ToutMyFuncin Tin, out Tout(Tin obj); MyFuncstring, string str5 t 农码一生; MyFuncobject, object str6 t 农码一生; MyFuncstring, object str7 t 农码一生;泛型接口的可变性接着看框架默认接口协变(子类-父类)IEnumerablestring list new Liststring(); IEnumerableobject list2 list;逆变父类- 子类IComparableobject list3 null; IComparablestring list4 list3;接下来我们试试自定泛型接口首先定义测试类型、接口// 人 public class People { } //老师(继承People[人]) public class Teacher : People { } //运动 public interface IMotionT { } //跑步 public class RunT : IMotionT { }然后我们测试协变性同样我们需要把接口 interface IMotionT 定义为 interface IMotionout T//运动 public interface IMotionout T{}IMotionTeacher x new RunTeacher(); IMotionPeople y x;如果我们要测试逆变性则需要把 interface IMotionT 定义为 interface IMotionin T//运动 public interface IMotionin T{}IMotionPeople x2 new RunPeople(); IMotionTeacher y2 x2;泛型接口的逆变编译后同样进行了强制转换当然我们也可以直接写成IMotionTeacher y3 new RunPeople();