• 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 : 泛型参数只能作为输入参数类型,不能作为输出(方法返回值)
















  • 相关阅读:
    学习笔记5_Day09_网站访问量统计小练习
    学习笔记4_ServletContext(重要整个Web应用的动态资源之间共享数据)
    学习笔记03_Day09-----Servle与反射()
    学习笔记2_Day09_servlet的细节
    学习笔记1_Day09_Servlet
    OC对数组排序的方法
    sqlite事务处理
    封装数据库
    JsonModel的使用
    RBAC表
  • 原文地址:https://www.cnblogs.com/hanjun0612/p/9779756.html
Copyright © 2020-2023  润新知