图文详解C#中的协变与逆变

 更新时间:2022年02月06日 09:28:26   作者:阿辉  
“协变”是指能够使用与原始指定的派生类型相比,派生程度更大的类型,“逆变”则是指能够使用派生程度更小的类型,这篇文章主要给大家介绍了关于C#中协变与逆变的相关资料,需要的朋友可以参考下

前言

这篇文章简单说说C#中的协变和逆变。

在C#编程中,由于存在类型之间的强制转换,很容易会出现所谓的类型可变性说法,存在协变、逆变、不变三种。

就比如前一篇文章介绍的泛型概念,如果创建了泛型类型的实例,编译器会接受泛型类型声明以及类型参数来创建构造类型。但是在日常使用过程中,我们可能会将派生类型分配给基类型的变量,有时候会出现错误。

这里就存在一个赋值兼容性问题。

每一个变量都有一种类型,可以将派生类对象的实例赋值给基类变量(好比之前子类声明的变量可以赋值给父类声明的变量一样)。

如下所示:

        class People
        {
            public int Age = 27;
        }
 
        class AhuiPeople : People
        {
 
        }

 

            People ahui = new People();
            People people = new AhuiPeople();
 
            Console.WriteLine("Age:"+people.Age);
            Console.ReadKey();

协变和逆变

我们按照同样的逻辑,在泛型委托中进行这种强类型的转换,会发现即使基类和派生类之间可以进行正常的转换,但是委托之间不能进行转换会出现异常错误提示。

具体如下代码所示:

        delegate T AgeDelegate<T>();         
 
        static AhuiPeople GetAge()
        {
            return new AhuiPeople();
        }

在转换过程中,委托的具体用法,但是这样子编译器提示错误。

            AgeDelegate<AhuiPeople> ahui = GetAge;
            AgeDelegate<People> people = ahui;

错误提示

这就是上面解释的那样子,基类和派生类之间可以进行转换但是委托之间未存在关联,无法进行强制类型的转换。
那么想解决这个问题就引入了协变来解决。

如果派生类只是用于输出值,那么这种结构化的委托有效性之间的常数关系叫做协变,可通过主动告知编译器我们的期望,使用Out关键字标记委托声明中的类型参数。

        delegate T AgeDelegate<out T>();   

修改成这样子后,上面错误演示的代码编译器就可以正常编译通过了。

上面简单介绍了协变,那么接下来我们来看逆变是什么。

其实逆变就是在委托中既要声明委托类型,也要在委托方法中有实参。

这种在期望传入基类时允许传入派生对象的特性叫做逆变。 逆变使用关键字in来标记。

具体如下代码所示:

        delegate void AgeDelegate<in T>(T p); 
        static void GetAge(People p)
        {
            Console.WriteLine(p.Age);
        }
            AgeDelegate<People> ahui = GetAge;
            AgeDelegate<AhuiPeople> people = ahui;
 
            people(new AhuiPeople());
            Console.WriteLine();
            Console.ReadKey();

输出结果

既然协变和逆变可以使用在委托上,那么接口上也可以使用,此时也需要使用out和in关键字。

总结

到此这篇关于C#中协变与逆变的文章就介绍到这了,更多相关C#协变与逆变内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • c# winform 解决PictureBox 无法打印全部图片的问题

    c# winform 解决PictureBox 无法打印全部图片的问题

    这篇文章主要介绍了c# winform 解决PictureBox 无法打印全部图片的问题,帮助大家更好进行c# winform开发,感兴趣的朋友可以了解下
    2020-12-12
  • .net后台获取html控件值的2种方法

    .net后台获取html控件值的2种方法

    .net后台获取html控件值的2种方法,需要的朋友可以参考一下
    2013-04-04
  • C#中的IEnumerable简介及简单实现实例

    C#中的IEnumerable简介及简单实现实例

    这篇文章主要介绍了C#中的IEnumerable简介及简单实现实例,本文讲解了IEnumerable一些知识并给出了一个简单的实现,需要的朋友可以参考下
    2015-03-03
  • C#使用正则表达式过滤html标签

    C#使用正则表达式过滤html标签

    最近在开发一个项目,其中有需求要求我们把一段html转换为一般文本返回,使用正则表达式是明智的选择,下面小编给介绍下C#使用正则表达式过滤html标签,需要的朋友参考下
    2016-08-08
  • winform实现限制及解除鼠标移动范围的方法

    winform实现限制及解除鼠标移动范围的方法

    这篇文章主要介绍了winform实现限制及解除鼠标移动范围的方法,涉及C#控制WinForm鼠标事件属性的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-09-09
  • C#判断单词个数方法总结

    C#判断单词个数方法总结

    我们给大家总计了C#中判断英文单词个数的方法以及排序的技巧,对此有需要的朋友可以测试下。
    2018-03-03
  • C#利用FluentFTP实现FTP上传下载功能详解

    C#利用FluentFTP实现FTP上传下载功能详解

    FTP作为日常工作学习中,非常重要的一个文件传输存储空间,想必大家都非常的熟悉了,那么如何快速的实现文件的上传下载功能呢,本文以一个简单的小例子,简述如何通过FluentFTP实现文件的上传和下载功能
    2023-02-02
  • C#仿Windows XP自带的扫雷游戏

    C#仿Windows XP自带的扫雷游戏

    这篇文章主要为大家详细介绍了C#仿Windows XP自带的扫雷游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-04-04
  • C#中前台线程和后台线程的区别与联系

    C#中前台线程和后台线程的区别与联系

    这篇文章主要介绍了C#中前台线程和后台线程的区别与联系,本文先讲解了它们的区别,然后给出了一个例子来验证这些区别,需要的朋友可以参考下
    2015-06-06
  • 浅谈C# StringBuilder内存碎片对性能的影响

    浅谈C# StringBuilder内存碎片对性能的影响

    这篇文章主要介绍了浅谈StringBuilder内存碎片对性能的影响,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03

最新评论