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

    泛型接口中的泛型参数可以声明为协变参数或者逆变参数,首先介绍一下泛型接口的协变和逆变:

    •   协变:泛型参数定义的类型只能作为方法的返回类型,不能用作方法参数的类型,且该类型直接或间接地继承自接口方法的返回值类型,称为协变。可以使用关键字out,将泛型类型参数声明为协变参数。
    •   逆变:泛型参数定义的类型只能作为方法参数的类型,不能用作返回类型,且该类型是接口方法的参数类型的基类型,称为逆变。可以使用in关键字,将泛型类型参数声明为逆变参数。

    首先我们来定义一个协变接口,代码如下所示:

     具有协变参数的泛型接口
    1
    interface ISample1<out T>
    2 {
    3 T Function1();
    4 }
    5
    6 class Sample1<T>:ISample1<T>
    7 {
    8 public T Function1()
    9 {
    10 Console.WriteLine("Wroked......");
    11 return default(T);
    12 }
    13 }

    上述代码中,ISample1<out T>是一个协变接口,其泛型参数T是一个协变参数,Sample1 <T>泛型类实现了该协变接口,如下代码体现了“协变”:

    1 class BaseClass{}
    2 class Child:BaseClass{}
    3 ISample1<Child> sample1=new ISample<Child>(); <1>
    4 ISample1<BaseClass> base1=sample1; <2>
    5 ISample1<object> base2=base1; <3>

    在上述代码中,<1>中sample1的协变参数的类型为Child(此时是协变实参),也就是<1>中sample1的接口方法返回类型为Child,二<2>中的接口方法返回类型为BaseClass,CLR会自动完成Child到BaseClass的隐式类型转换,此谓“协变”。同理,<3>也是合法的。
        我们特别介绍一下第一段代码中的“default(T)”代码,在这里default关键字用以解决这样一个问题:在无法预参数化类型T是值类型还是引用类型的情况下,使用default关键字,对于引用类型会返回空引用(null),而对于值类型则会返回0。

    具有逆变参数的泛型接口
    1
    interface ISample2<in T>
    2 {
    3 void Function2(T arg);
    4 }
    5 class Sample2<T> : ISample2<T>
    6 {
    7 public void Function2(T arg)
    8 {
    9 Console.WriteLine(arg);
    10 }
    11 }


    上述代码定义了一个逆变接口,以及一个实现了该接口的类。接下来,首先使用BaseClass作为类型实参声明,并初始化一个变量sample2,然后再使用Child作为类型实参声明一个变量sample3,Child类是BaseClass类的派生类,可以基于逆变的规则将sample2赋给sample3变量

    1 ISample2<BaseClass> sample2 = new Sample2<BaseClass>();
    2 ISample2<Child> sample3 =sample2;




  • 相关阅读:
    [已解决] Python logging 重复打印日志信息
    scrapy
    Python 元编程
    MySQL性能优化 分区
    SQL Mode
    Golang 接口
    Python partial
    栈、队列(链表实现)
    Golang 位向量
    Java50题——学习以及思考
  • 原文地址:https://www.cnblogs.com/hesitate/p/2436615.html
Copyright © 2011-2022 走看看