• 热门专题

关于C#中的协变和逆变的详细介绍

作者:whl  发布日期:2018-12-13 08:30:00
  •     小编经常收到一些网友的求助说自己不知道怎么搞的协变和逆变总是傻傻分不清,因此搞错了很多代码,为此小编特意进行了资料整理,下面就以详细的代码为例,来给大家区分一下两者到底哪里不一样。

    什么是协变与逆变

    MSDN的解释:

    协变和逆变都是术语,前者指能够使用比原始指定的派生类型的派生程度更小(不太具体的)的类型,后者指能够使用比原始指定的派生类型的派生程度更大(更具体的)的类型。

    泛型类型参数支持协变和逆变,可在分配和使用泛型类型方面提供更大的灵活性。

    一开始我总是分不清协变和逆变,因为MSDN的解释实在是严谨有余而易读不足。

    其实从中文的字面上来理解这两个概念就挺容易的了:

    "协变"即"协调的转变","逆变"即"逆向的转变"。

    下面来一起看看详细的介绍吧

    C#中的协变与逆变

    一、使用协变(Covariance)和逆变(Contravariance )能够实现数组之间、委托实例和方法之间、泛型委托实例之间、泛型接口的变量和泛型类型的对象之间、泛型接口的变量之间的隐式转换;使用协变将允许使用比原指定类型派生程度更大(即更具体的)的类型,使用逆变将允许使用比原指定类型派生程度更小(即更不具体的)的类型;

    1.协变和逆变都只支持引用类型,不支持值类型;

    2.如果泛型接口或泛型委托的类型参数被声明为协变或逆变,则该泛型接口或泛型委托被称为变体(Variant);

    二、数组只支持协变,即支持派生程度更大的类型的数组隐式转换为派生程度更小的类型的数组:

    数组转换为派生程度更小的类型的数组

    1.此操作不是类型安全的,给上述数组添加原数组不兼容的对象时会抛出异常ArrayTypeMismatchException:

    //myArray[0] = 10; //此处10会被装箱为object类型,而object类型的对象不能隐式转换为string类型

    2.由于值类型不支持协变和逆变,因此下面的转换是错误的:

    //object[] myArray = new int[5];

    //IComparable[] myOtherArray = new int[5];

    三、委托支持协变和逆变,为匹配委托类型和方法签名提供更大的灵活性,不仅可以将签名完全匹配的方法分配给委托实例,还可以通过协变将返回值类型与委托类型的返回值类型相比派生程度更大的方法分配给委托实例;通过逆变将参数类型与委托类型的参数类型相比派生程度更小的方法分配给委托实例:

    逆变綒喎rss7K/cDg0M3T686vzdDA4NDN" src="http://www.it165.net/uploadfile/2018/1212/20181212123529729.bmp" style="width: 382px; height: 150px;" />

    四、在定义泛型委托时,可以通过将类型参数声明为逆变量或协变量来定义变体委托(Variant Delegate),从而使具有协变和逆变转换关系的不用类型的泛型委托实例之间进行隐式转换,使用关键字out修饰返回值的类型参数以支持协变,使用关键字in修饰参数的类型参数以支持逆变:

    使用关键字in修饰参数

    1.变体委托不支持合并,即Delegate.Combine方法需要委托的类型完全相同才能合并,不支持变体委托的转换;在运行时合并不同类型的变体委托会抛出异常System.ArgumentException;

    五、在定义泛型接口时,可以通过将类型参数声明为逆变量或协变量来定义变体接口(Variant Interface),协变允许方法的返回值类型比接口定义中返回值类型参数的派生程度更大,逆变允许方法的参数类型比接口定义中参数类型参数的派生程度更小;使用关键字out修饰返回值的类型参数以支持协变,使用关键字in修饰参数的类型参数以支持逆变:

    使用关键字in修饰参数的类型参数以支持逆变

    1.实现变体接口的类型仍然是不可变量;

    总结

    好了,今天给大家介绍的关于C#中的协变逆变如何区分就到此为止了,相信大家通过上面这些内容的学习应该能很好的区分不会再搞混了。如果大家对于上述内容还有什么不明白的关系留言,小编会及时进行讲解的。

     
About IT165 - 广告服务 - 隐私声明 - 版权申明 - 免责条款 - 网站地图 - 网友投稿 - 联系方式
本站内容来自于互联网,仅供用于网络技术学习,学习中请遵循相关法律法规