微软官方概述:

在C#中,协变和逆变能够实现数组类型、委托类型和泛型类型参数的隐式引用转换。协变保留分配兼容性,逆变则与之相反。

协变:能够使用与原始指定的派生类型相比,派生程度更大的类型。

逆变:能够使用派生程度更小的类型。

官方示例:

string str = "test";
object obj = str; IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings; static void SetObject(object){}
Action<object> actObject = SetObject;
Action<string> actString = actObject;

上面示例中,从 string --> object 的隐式转换这是协变;如果从 object --> string 转换这是逆变。

数组协变

string[] str = new string[10];
object[] array = str;

这是一种不安全的操作,在对 array数组赋值时,array[0] = 0; 在编译时可以通过,但是在运行时会提示错误。“System.ArrayTypeMismatchException:“尝试访问类型与数组不兼容的元素。””。这里的array 只是保存了str的引用,仍然是一个string类型的数组。

委托中的协变和逆变

对方法组的协变和逆变支持将方法签名与委托类型相匹配。这样不仅可以将具有匹配签名的方法分配给委托,还可以分配与委托类型指定的派生类型相比,返回派生程度更大的类型的方法(协变)或者如果方法所接受参数的派生类型所具有的程度小于委托类型指定的程度(逆变),也可将其分配给委托。这就包含泛型委托和非泛型委托。

class People {}
class Student:People{}
delegate People Method();
class Program
{ People peopleMethod(){}
Student studetnMethod(){} static void Test(){
Method method = peopleMethod;
Method method2 = studentMethod;
}
}

上面的委托Method(),返回值类型是People,但是我们采用更加具体的student类型也是可以的,由student --> People类型的转换,这是正常的多态行为。委托的目标方法可能返回比委托声明的返回值类型更加特定的返回值类型,这称为协变。

那么当我们也可以采用一个比目标方法参数类型更加具体的参数类型,这称为逆变。

下面的示例:

delegate void StringAction (string s);

class Test{
static void Main(){
StringAction sa = new StringAction (ActionObject);
sa("hi"); }
static void ActionObject(object o) => Console.WriteLine(o);
}

C# 4.0添加了 out 和 in 关键字,来分别支持协变和逆变。

泛型中的协变和逆变,单独介绍

C# 协变、逆变的更多相关文章

  1. 解读经典《C#高级编程》最全泛型协变逆变解读 页127-131.章4

    前言 本篇继续讲解泛型.上一篇讲解了泛型类的定义细节.本篇继续讲解泛型接口. 泛型接口 使用泛型可定义接口,即在接口中定义的方法可以带泛型参数.然后由继承接口的类实现泛型方法.用法和继承泛型类基本没有 ...

  2. C#中泛型方法与泛型接口 C#泛型接口 List<IAll> arssr = new List<IAll>(); interface IPerson<T> c# List<接口>小技巧 泛型接口协变逆变的几个问题

    http://blog.csdn.net/aladdinty/article/details/3486532 using System; using System.Collections.Generi ...

  3. C#的in/out关键字与协变逆变

    C#提供了一组关键字in&out,在泛型接口和泛型委托中,若不使用关键字修饰类型参数T,则该类型参数是不可变的(即不允许协变/逆变转换),若使用in修饰类型参数T,保证"只将T用于输 ...

  4. Programming In Scala笔记-第十九章、类型参数,协变逆变,上界下界

    本章主要讲Scala中的类型参数化.本章主要分成三个部分,第一部分实现一个函数式队列的数据结构,第二部分实现该结构的内部细节,最后一个部分解释其中的关键知识点.接下来的实例中将该函数式队列命名为Que ...

  5. java协变逆变,PECS

    public static void main(String[] args) { // Object <- Fruit <- Apple <- RedApple System.out ...

  6. 协变 & 逆变

    都跟里氏替换原则有关. 协变:你可以用一个子类对象去替换相应的一个父类对象,这是完全符合里氏替换原则的,和协(谐)的变.如:用Swan替换Bird. 逆变:你可以用一个父类对象去替换相应的一个子类对象 ...

  7. C#核心语法讲解-泛型(详细讲解泛型方法、泛型类、泛型接口、泛型约束,了解协变逆变)

    泛型(generic)是C#语言2.0和通用语言运行时(CLR)的一个新特性.泛型为.NET框架引入了类型参数(type parameters)的概念.类型参数使得设计类和方法时,不必确定一个或多个具 ...

  8. C#核心语法-泛型(详细讲解泛型方法、泛型类、泛型接口、泛型约束,了解协变逆变)

    泛型(generic)是C#语言2.0和通用语言运行时(CLR)的一个新特性.泛型为.NET框架引入了类型参数(type parameters)的概念.类型参数使得设计类和方法时,不必确定一个或多个具 ...

  9. C# 协变out 、逆变 in

    需求:泛型使用多态性 备注:协变逆变只能修饰 接口和委托 简单理解: 1.使用 in 修饰后为逆变,只能用作形参使用 ,参考 public delegate void Action<in T&g ...

  10. 编写高质量代码改善C#程序的157个建议[协变和逆变]

    前言 本文已更新至http://www.cnblogs.com/aehyok/p/3624579.html .本文主要学习记录以下内容: 建议42.使用泛型参数兼容泛型接口的不可变性 建议43.让接口 ...

随机推荐

  1. SQL server已经设置为单用户模式,还是无法做分离、属性设置等操作

    https://www.cnblogs.com/xingyunqiu/p/10336938.html SQL server已经设置为单用户模式,Sql server还原失败数据库正在使用,无法获得对数 ...

  2. TCP协议如何保证可靠传输?

    一.TCP的可靠传输如何保证? 在TCP连接中,数据流必须以正确的顺序传送给对方.TCP的可靠性是通过顺序编号和确认(ACK)实现的.TCP在开始传送一个段时,为准备重传而首先将该段插入到发送队列中, ...

  3. jQuery的选择器总结

    jQuery的选择器 不会返回undefined或null 基本选择器 id选择器:$('#id') element选择器:$('elem') class选择器:$('.class') 通配符选择器: ...

  4. JavaWeb之servlet(2)

    servlet(2) ServletContext servlet的上下文 每个jvm的虚拟机中的每个web工程都只有一个ServletContext工程,即在一个web工程中,无论写了多少个Java ...

  5. 6.python3实用编程技巧进阶(一)

    1.1.如何在列表中根据条件筛选数据 # 1.1.如何在列表中根据条件筛选数据 data = [-1, 2, 3, -4, 5] #筛选出data列表中大于等于零的数据 #第一种方法,不推荐 res1 ...

  6. [Linux] SSH隧道本地端口转发访问远程服务中的数据库

    当我的本地没有安装任何数据库服务的时候,可以直接通过我本地的端口访问远程机器上的数据库服务,实现这样的效果就可以使用本地转发功能 实际测试本地端口转发,把本地的9006端口转发给远程服务器的115.1 ...

  7. python爬虫(2)——urllib、get和post请求、异常处理、浏览器伪装

    urllib基础 urlretrieve() urlretrieve(网址,本地文件存储地址) 直接下载网页到本地 import urllib.request #urlretrieve(网址,本地文件 ...

  8. 在Rust中,cargo使用国内镜像源

    一个编程语言依赖包管理的普通问题. cargo解决得比较优雅. 一,新建$HOME/.cargo/config文件 [source.crates-io] registry = "https: ...

  9. java.sql.Date赋值给了java.util.Date.转化成JSONArray时出错net.sf.json.JSONException: java.lang.reflect.InvocationTargetException

    net.sf.json.JSONException: java.lang.reflect.InvocationTargetExceptionat net.sf.json.JSONObject.defa ...

  10. Node.js Koa2开发微信小程序服务端

    1.promise.async.await const Koa = require('koa') const app = new Koa() // 应用程序对象 有很多中间件 // 发送HTTP KO ...