C# - 协变、逆变 看完这篇就懂了
1. 基本概念
官方:协变和逆变都是术语,前者指能够使用比原始指定的派生类型的派生程度更大(更具体的)的类型,后者指能够使用比原始指定的派生类型的派生程度更小(不太具体的)的类型。[MSDN]
公式:
协变:IFoo<父类> = IFoo<子类>;
逆变:IBar<子类> = IBar<父类>;
暂时不理解没关系,您接着往下看。
2. 协变(Covariance)
1) out关键字
对于泛型类型参数,out
关键字可指定类型参数是协变的。 可以在泛型接口和委托中使用 out
关键字。[MSDN]
2) 鲁迅:一张图胜过千言万语(图小看不清,单机鼠标右键 -> 在新标签页中打开图片)
备注:泛型委托的斜变原理也是一样的。
3) 什么是协变?
斜变就是对具体成员的输出参数进行一次类型转换,且类型转换的准则是 “里氏替换原则”。
3. 逆变(Contravariance)
1) in关键字
对于泛型类型参数,in
关键字可指定类型参数是逆变的。 可以在泛型接口和委托中使用 in
关键字。[MSDN]
2) 鲁迅:一张图胜过千言万语(图小看不清,单机鼠标右键 -> 在新标签页中打开图片)
3) 什么是逆变?
逆变就是对具体成员的输入参数进行一次类型转换,且类型转换的准则是 “里氏替换原则”。
4. 自问自答
1)协变、逆变 为什么只能针对泛型接口或者委托?而不能针对泛型类?
因为它们都只能定义方法成员(接口不能定义字段),而方法成员在创建对象的时候是不涉及到对象内存分配的,所以它们是类型(内存)安全的。
为什么不针对泛型?因为泛型类是模板类,而类成员是包含字段的,不同类型的字段是影响对象内存分配的,没有派生关系的类型它们是不兼容的,也是内存不安全的。
2)协变、逆变 为什么是类型安全的?
本质上是里氏替换原则,由里氏替换原则可知:派生程度小的是派生程度大的子集,所以子类替换父类的位置整个程序功能都不会发生改变。
3)官方对 协变、逆变 的定义现在是否能看懂?
上面看懂了,官方定义肯定也是没问题的。派生程度小可以理解为基类,派生程度大可以理解为子类或派生类,至于为什么用程度这个词,是因为继承链的深度是没限制的。
最新文章
- PHP基础语法
- C# 不同版本切版时,方法不支持,加载对应dll, 相关Dll的资源
- Js中 关于top、clientTop、scrollTop、offsetTop的用法
- axis2学习, ant 构建axis2 ws
- Kafka小记
- 简单的Ajax
- WebService之CXF注解报错(一)
- MySQL数据库基础(三)(操作数据表中的记录)
- matplotlib种类
- shell脚本示例:计算毫秒级、微秒级时间差
- linux cent os 6.5安装Nginx
- note 2 运算符和表达式
- 洛谷.1110.[ZJOI2007]报表统计(Multiset Heap)
- android: 接收系统广播
- Presto上使用SQL遇到的一些坑
- s5-2 Cpu调度算法
- 如何从GitHub迁移到GitLab?
- Sysstat的工具集sar、 iostat、mpstat、sadf、sar、sadc
- Spark SQL -- Hive
- PHP删除数组中空值
热门文章
- Shiro在Web环境下集成Spring的大致工作流程
- 为什么选择 Spring 作为 Java 框架
- Android解决RecyclerView中的item显示不全方案
- HashMap源码之resize
- [剑指offer] 53. 表达数值的字符串
- 使用nginx+tomcat实现动静分离
- 【iOS】ERROR ITMS-90032: ";Invalid Image Path...
- DES、3DES、AES、PBE对称加密算法实现及应用
- codeforces 339A.Helpful Maths B.Xenia and Ringroad 两水题
- UE4 本地化不起作用 SetCurrentCulture