为了账号安全,请及时绑定邮箱和手机立即绑定

详解C#的协变和逆变

标签:
C#

  一、使用协变(Covariance)和逆变(Contravariance )能够实现数组之间、委托实例和方法之间、泛型委托实例之间、泛型接口的变量和泛型类型的对象之间、泛型接口的变量之间的隐式转换;使用协变将允许使用比原指定类型派生程度更大(即更具体的)的类型,使用逆变将允许使用比原指定类型派生程度更小(即更不具体的)的类型;
  1.协变和逆变都只支持引用类型,不支持值类型;
  2.如果泛型接口或泛型委托的类型参数被声明为协变或逆变,则该泛型接口或泛型委托被称为变体(Variant);

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

object[] myArray = new string[5];
IComparable[] myOtherArray = new string[5];

  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;

原文作者:Minotauros

原文地址:https://www.cnblogs.com/minotauros/p/10090701.html

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
JAVA开发工程师
手记
粉丝
33
获赞与收藏
206

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消