zoukankan      html  css  js  c++  java
  • C# 协变和逆变

    今天谈一谈协变和逆变。

    协变:通过协变,可以使用与泛型参数指定的派生类型相比,派生程度更大的类型。 这样可以对委托类型和实现变体接口的类进行隐式转换。 引用类型支持协变和逆变,但值类型不支持

    逆变:通过逆变,可以使用与泛型参数指定的派生类型相比,派生程度更小的类型。 这样可以对委托类型和实现变体接口的类进行隐式转换。 引用类型支持泛型类型参数中的协变和逆变,但值类型不支持


    首先看代码:

            public interface MyTest<T> { }
    
            public class A { }
            public class B :A { }

    我们创建了基类A,派生类B。

    接着我们可以很轻易的使用如下代码:

                A a = new A();
                B b = new B();
                a = b;

    那么问题来了。当我们使用MyTest<A>和MyTest<B>时

                     MyTest<A> a = null;
                MyTest<B> b = null;
                a = b;

    这样就会报错。无法将类型“MyTest<TestApp.Program.B>”隐式转换为“MyTest<TestApp.Program.A>”

    原因是因为,虽然A和B有继承关系,

    但在万物皆对象的OOP语言中,MyTest<A>和MyTest<B>并没有继承关系!我们把MyTest<A>和MyTest<B>分别看做了2个整体对象。


    然后 微软 引入了 协变和逆变。

    PS:协变和逆变目前只支持泛型接口和委托

    关键字是 : out 和 in


    上面的代码,我们修改一下

    public interface MyTest<out T> { }
    
            public class A { }
            public class B :A { }


    创建了一个 接口,并且使用了out关键字

    MyTest<A> a = null;
                MyTest<B> b = null;
                a = b;
                

    这样我们发现,就没有问题了。这就是协变


    那我们想要使b=a呢?

    public interface MyTest<in T> { }
    
            public class A { }
            public class B :A { }

    聪明的你一定知道了,使用in关键字

    MyTest<A> a = null;
                MyTest<B> b = null;
                b = a;

    这样也就搞定了。


    不过协变和逆变需要注意使用:

    协变 out :泛型参数只能作为输出类型(方法返回值),不能作为输入参数。

    逆变 in : 泛型参数只能作为输入参数类型,不能作为输出(方法返回值)
















  • 相关阅读:
    理解全虚拟、半虚拟以及硬件辅助的虚拟化
    使用PowerShell向SharePoint中写入数据
    Python的时间模块小结(转自:不懂真人)
    Windows下如何安装Python的第三方库
    Python的正则表达式笔记
    PG, Pool之间的一些数量关系
    Ceph与OpenStack的Nova相结合
    rbd命令
    rados命令
    ceph命令
  • 原文地址:https://www.cnblogs.com/hanjun0612/p/9779756.html
Copyright © 2011-2022 走看看