对于泛型的知识,一直比较模糊,现在有机会整理一下,突发发现C#还有很多你不知道的东东,继续.NET FrameWork中泛型的协变与逆变:

1. 可变性的类型:协变性和逆变性

可变性是以一种类型安全的方式,将一个对象当做另一个对象来使用。如果不能将一个类型替换为另一个类型,那么这个类型就称之为:不变量。协变和逆变是两个相互对立的概念:

  • 如果某个返回的类型可以由其派生类型替换,那么这个类型就是支持协变的
  • 如果某个参数类型可以由其基类替换,那么这个类型就是支持逆变的。

2. C# 4.0对泛型可变性的支持

在C# 4.0之前,所有的泛型类型都是不变量——即不支持将一个泛型类型替换为另一个泛型类型,即使它们之间拥有继承关系,简而言之,在C# 4.0之前的泛型都是不支持协变和逆变的。

C# 4.0通过两个关键字:out和in来分别支持以协变和逆变的方式使用泛型。

3. C#中泛型可变性的限制

1. 不支持类的类型参数的可变性

只有接口和委托可以拥有可变的类型参数。in 和 out 修饰符只能用来修饰泛型接口和泛型委托。

2. 可变性只支持引用转换

可变性只能用于引用类型,禁止任何值类型和用户定义的转换,如下面的转换是无效的:

  • 将 IEnumerable<int> 转换为 IEnumerable<object> ——装箱转换
  • 将 IEnumerable<short> 转换为 IEnumerable<int> ——值类型转换
  • 将 IEnumerable<string> 转换为 IEnumerable<XName> ——用户定义的转换

3. 类型参数使用了 out 或者 ref 将禁止可变性

对于泛型类型参数来说,如果要将该类型的实参传给使用 out 或者 ref 关键字的方法,便不允许可变性,如:

delegate void someDelegate<in T>(ref T t)

4. 可变性必须显式指定

从实现上来说编译器完全可以自己判断哪些泛型参数能够逆变和协变,但实际却没有这么做,这是因为C#的开发团队认为:

必须由开发者明确的指定可变性,因为这会促使开发者考虑他们的行为将会带来什么后果,从而思考他们的设计是否合理。

5. 注意破坏性修改

在修改已有代码接口的可变性时,会有破坏当前代码的风险。例如,如果你依赖于不允许可变性的is或as操作符的结果,运行在.NET 4时,代码的行为将有所不同。同样,在某些情况下,因为有了更多可用的选项,重载决策也会选择不同的方法。所以在对已有代码引入可变性时要做好足够的单元测试以及防御措施。

6. 多播委托与可变性不能混用

下面的代码能够通过编译,但是在运行时会抛出 ArgumentException 异常:

Func<string> stringFunc = () => "";
Func<object> objectFunc = () => new object();
Func<object> combined = objectFunc + stringFunc;

这是因为负责链接多个委托的 Delegate.Combine方法要求参数必须为相同的类型。上面的示例我们可以修改成如下正确的代码:

Func<string> stringFunc = () => "";
Func<object> defensiveCopy = new Func<object>(stringFunc);
Func<object> objectFunc = () => new object();
Func<object> combined = objectFunc + defensiveCopy;

推荐文章:

http://www.cnblogs.com/oujinliang/archive/2009/11/30/1613985.html

IOC推荐:

http://developer.51cto.com/art/201107/276775_all.htm

转载于:https://www.cnblogs.com/xibei666/p/5451793.html

泛型--协变与逆变(转)相关推荐

  1. C# 泛型的协变和逆变

    1. 可变性的类型:协变性和逆变性 可变性是以一种类型安全的方式,将一个对象当做另一个对象来使用.如果不能将一个类型替换为另一个类型,那么这个类型就称之为:不变量.协变和逆变是两个相互对立的概念: 如 ...

  2. 泛型型协变逆变_Java泛型类型简介:协变和逆变

    泛型型协变逆变 by Fabian Terh 由Fabian Terh Java泛型类型简介:协变和逆变 (An introduction to generic types in Java: cova ...

  3. [转载] JAVA泛型杂谈--擦除,协变,逆变,通配符等

    参考链接: Java中的协变返回类型 在<JAVA核心思想>这本书里,关于泛型的章节意外的很多,小小的泛型里其实有很多可以学习的内容,我总结下最近看书的成果. 一. 泛型的好处和应用 最基 ...

  4. java泛型的逆变_Java泛型的协变与逆变

    泛型擦除 Java的泛型本质上不是真正的泛型,而是利用了类型擦除(type erasure),比如下面的代码就会出现错误: 报的错误是:both methods  have same erasure ...

  5. Java 泛型的协变与逆变

    协变.逆变.抗变 协变,逆变,抗变等概念是从数学中来的,在编程语言Java/Kotlin/C#中主要应用在泛型上.描述的是两个类型集合之间的继承关系. 第一个集合为:Animal.Dog , Dog ...

  6. Java泛型的协变与逆变

    泛型擦除 Java的泛型本质上不是真正的泛型,而是利用了类型擦除(type erasure),比如下面的代码就会出现错误: 报的错误是:both methods  have same erasure ...

  7. .NET可变性解析(协变和逆变)

    [一]何为可变性 可变性是.NET4.0中的一个新特性,可变性可分为 : 协变性.逆变性.不可变性. 那么在.NET4.0之前是否有可变性? 答案是肯定的,我们可以通过下面的几个实例来简单的了解一下. ...

  8. 深入理解 C# 协变和逆变【转】

    msdn 解释如下: "协变"是指能够使用与原始指定的派生类型相比,派生程度更大的类型. "逆变"则是指能够使用派生程度更小的类型. 解释的很正确,大致就是这样 ...

  9. C#中协变和逆变的基本概念、List和List.Select方法的命名空间

    在 C# 中,协变和逆变能够实现数组类型.委托类型和泛型类型参数的隐式引用转换. 协变保留分配兼容性,逆变则与之相反. msdn 解释如下: "协变"是指能够使用与原始指定的派生类 ...

最新文章

  1. thymeleaf+layui 展示table 报500
  2. 7 OC 中class 类的结构
  3. Handler消息机制(十):HandlerThread源码解析
  4. perl的Getopt::Long和pod::usage
  5. 你的「所见所闻」,才是电视的核心竞争力
  6. 软件测试用python一般用来做什么-如何将Python应用到实际测试工作中?
  7. 机器学习实验中的编程技术(part4)--模型持久化
  8. 解密 RubyEncoder
  9. 联想P340加显卡白屏,降级BIOS恢复正常。
  10. javascript 逻辑运算符 和 或 非
  11. 看雪CTF.TSRC 2018 团队赛 第一题 初世纪 writeup
  12. Android版本与SDK 版本对应关系
  13. 苹果MacBook Air安装win7
  14. vue中使用antv/g6 绘制关系图、结构图
  15. STM32F407ZGT6的OLEDIIC的实现(全代码)
  16. 芯宇宙通用仓库管理系统V1.0说明书
  17. ****you do not have the permissions necessary t...
  18. AX7A200教程(3): DDR3突发读写
  19. 深度学习框架之PyTorch
  20. html5霓虹效果代码,纯CSS实现酷炫的霓虹灯效果(附demo)

热门文章

  1. 常见宽带错误解决方法
  2. 老弟,Redis 6.0 除了多线程,别忘了这个牛逼特性!
  3. 绝了!Dataway让 SpringBoot 变得更强大!
  4. 秒杀系统流量削峰,这事应该怎么做?
  5. Mybatis 的工作原理,写得太好了!
  6. 终于有篇看的懂的 B 树文章了!
  7. ServiceMesh究竟解决什么问题?
  8. MySQL 如何查找删除重复行?
  9. 为什么我们做分布式要用 Redis ?
  10. 【Scratch】青少年蓝桥杯_每日一题_6.01_画春花