详解C#的协变和逆变
一、使用协变(Covariance)和逆变(Contravariance )能够实现数组之间、委托实例和方法之间、泛型委托实例之间、泛型接口的变量和泛型类型的对象之间、泛型接口的变量之间的隐式转换;使用协变将允许使用比原指定类型派生程度更大(即更具体的)的类型,使用逆变将允许使用比原指定类型派生程度更小(即更不具体的)的类型;
1.协变和逆变都只支持引用类型,不支持值类型;
2.如果泛型接口或泛型委托的类型参数被声明为协变或逆变,则该泛型接口或泛型委托被称为变体(Variant);
二、数组只支持协变,即支持派生程度更大的类型的数组隐式转换为派生程度更小的类型的数组:
object[] myArray = new string[];
IComparable[] myOtherArray = new string[];
1.此操作不是类型安全的,给上述数组添加原数组不兼容的对象时会抛出异常ArrayTypeMismatchException:
//myArray[0] = 10; //此处10会被装箱为object类型,而object类型的对象不能隐式转换为string类型
2.由于值类型不支持协变和逆变,因此下面的转换是错误的:
//object[] myArray = new int[5];
//IComparable[] myOtherArray = new int[5];
三、委托支持协变和逆变,为匹配委托类型和方法签名提供更大的灵活性,不仅可以将签名完全匹配的方法分配给委托实例,还可以通过协变将返回值类型与委托类型的返回值类型相比派生程度更大的方法分配给委托实例;通过逆变将参数类型与委托类型的参数类型相比派生程度更小的方法分配给委托实例:
public class MyBaseClass { }
public class MyClass : MyBaseClass { }
public class MyDerivedClass : MyClass { }
public delegate MyClass MyDelegate(MyClass obj);
public delegate T MyDelegate<T>(T obj);
//对于给定的方法
public staitc MyDerivedClass MyFunc(MyBaseClass obj)
{
return new MyDerivedClass();
}
//使用时:
MyDelegate myDelegate = MyFunc; //同时使用了协变和逆变
MyDelegate<MyClass> myDelegate = MyFunc;
四、在定义泛型委托时,可以通过将类型参数声明为逆变量或协变量来定义变体委托(Variant Delegate),从而使具有协变和逆变转换关系的不用类型的泛型委托实例之间进行隐式转换,使用关键字out修饰返回值的类型参数以支持协变,使用关键字in修饰参数的类型参数以支持逆变:
public delegate U MyDelegate<in T, out U>(T obj);
//使用时:
MyDelegate<MyClass,MyClass> myDelegate = MyFunc;
MyDelegate<MyBaseClass, MyDerivedClass> myOtherDelegate = MyFunc;
//隐式转换:
myDelegate = myOtherDelegate;
1.变体委托不支持合并,即Delegate.Combine方法需要委托的类型完全相同才能合并,不支持变体委托的转换;在运行时合并不同类型的变体委托会抛出异常System.ArgumentException;
五、在定义泛型接口时,可以通过将类型参数声明为逆变量或协变量来定义变体接口(Variant Interface),协变允许方法的返回值类型比接口定义中返回值类型参数的派生程度更大,逆变允许方法的参数类型比接口定义中参数类型参数的派生程度更小;使用关键字out修饰返回值的类型参数以支持协变,使用关键字in修饰参数的类型参数以支持逆变:
public interface IMyInterface<in T, out U>
{
U MyFunc();
void MyFoo(T obj);
}
public class MyClass<T, U> : IMyInterface<T, U>
{
public void MyFoo(T obj)
{
//do…
} }
//使用时:
IMyInterface<string, object> myObj = new MyClass<object, string>();
IMyInterface<object, string> myObj1 = new MyClass<object, string>();
myObj = myObj1;
1.实现变体接口的类型仍然是不可变量;
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的认可是我写作的最大动力!
作者:Minotauros
出处:https://www.cnblogs.com/minotauros/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
详解C#的协变和逆变的更多相关文章
- .Net中委托的协变和逆变详解
关于协变和逆变要从面向对象继承说起.继承关系是指子类和父类之间的关系:子类从父类继承所以子类的实例也就是父类的实例.比如说Animal是父类,Dog是从Animal继承的子类:如果一个对象的类型是Do ...
- C#4.0泛型的协变,逆变深入剖析
C#4.0中有一个新特性:协变与逆变.可能很多人在开发过程中不常用到,但是深入的了解他们,肯定是有好处的. 协变和逆变体现在泛型的接口和委托上面,也就是对泛型参数的声明,可以声明为协变,或者逆变.什么 ...
- C#协变和逆变
我们知道在C#中,是可以将派生类的实例赋值给基类对象的.
- C# 泛型的协变和逆变
1. 可变性的类型:协变性和逆变性 可变性是以一种类型安全的方式,将一个对象当做另一个对象来使用.如果不能将一个类型替换为另一个类型,那么这个类型就称之为:不变量.协变和逆变是两个相互对立的概念: 如 ...
- 不变(Invariant), 协变(Covarinat), 逆变(Contravariant) : 一个程序猿进化的故事
阿袁工作的第1天: 不变(Invariant), 协变(Covarinat), 逆变(Contravariant)的初次约 阿袁,早!开始工作吧. 阿袁在笔记上写下今天工作清单: 实现一个scala类 ...
- 再谈对协变和逆变的理解(Updated)
去年写过一篇博客谈了下我自己对协变和逆变的理解,现在回头看发现当时还是太过“肤浅”,根本没理解.不久前还写过一篇“黑”Java泛型的博客,猛一回头又是“肤浅”,今天学习Java泛型的时候又看到了协变和 ...
- 【转】c# 协变和逆变
本文转自:http://www.cnblogs.com/rr163/p/4047404.html C#的协变和逆变 由子类向父类方向转变是协变,用out关键字标识,由父类向子类方向转变是逆变,用in关 ...
- .NET 4.0中的泛型的协变和逆变
转自:http://www.cnblogs.com/jingzhongliumei/archive/2012/07/02/2573149.html 先做点准备工作,定义两个类:Animal类和其子类D ...
- 深入理解 C# 协变和逆变
msdn 解释如下: “协变”是指能够使用与原始指定的派生类型相比,派生程度更大的类型. “逆变”则是指能够使用派生程度更小的类型. 解释的很正确,大致就是这样,不过不够直白. 直白的理解: “协变” ...
随机推荐
- JavaSE基础知识(1)—初识Java
一.JAVA的背景 JAVA本身隶属的公司的是sun公司(创始公司) JAVA创始人:詹姆斯 高斯林 09年被oracle收购 JAVA的前身是Oak 二.JAVA的版本 95年 JAVA诞生96年 ...
- Connection lost: The server closed the connection
想必很多初学者都会遇到这个问题 其实很简单.mysql有个机制,就是8小时无通信,myslq就会自动关闭数据; 解决方案(2选1): 或者: 1.定时去做一个查询,就是 select * from X ...
- frp使用笔记
参考文档: https://github.com/fatedier/frp/blob/master/README_zh.md#%E9%80%9A%E8%BF%87-frpc-%E6%89%80%E5% ...
- iis 发布mvc
转载地址:https://www.cnblogs.com/Leo_wl/p/3866625.html
- 【Mybatis】MyBatis对表执行CRUD操作(三)
本例在[Mybatis]MyBatis配置文件的使用(二)基础上继续学习对表执行CRUD操作 使用MyBatis对表执行CRUD操作 1.定义sql映射xml文件(EmployeeMapper.xml ...
- 《Linux就该这么学》第二天课程
秦时明月经典语录:很多人被命运安排,而我安排命运.——卫庄 今天介绍了VM 虚拟机的安装以及Linux系统的安装,还讲解了Linux内核 RPM:降低软件的安装难度 源代码+安装规则→将程序源代码与安 ...
- ABP框架系列之四十:(Notification-System-通知系统)
Introduction Notifications are used to inform users on specific events in the system. ASP.NET Boiler ...
- springmvc接收数组方式总结
1.接受正常的数组 如param1=aaa¶m1=bbb¶m1=3 对于这种,在实体参数中,使用String param1[] 这种参数既可以获取数组的值 2.接受数组 ...
- sshpass 使用方法
首先下载sshpass并且安装 $ tar -zxvf sshpass-1.06.tar.gz $ cd sshpass-1.06 $ ./configure --prefix=/usr/local/ ...
- Oracle实现like多个值的查询
问题背景描述: 某天客户有一个需求,给定一批的手机号码或者电话号码,查询出相关的通话记录,以及相关的一些信息. 客户给定的被叫号码如图所示: 查询出来的结果如下图所示(本批次的结果不是上图导入的结 ...