美文网首页
C# 中泛型接口的协变和逆变(抗变)

C# 中泛型接口的协变和逆变(抗变)

作者: 黑山老雕 | 来源:发表于2019-08-26 22:27 被阅读0次

在C#中声明泛型接口时,我们可以使用 in 和 out 参数来控制这个泛型是协变还是逆变的,这里逆变有时也被翻译成抗变,协变和逆变是用来描述如果泛型存在继承关系时,两个泛型类是否能够直接赋值的问题。比如派生泛型 IInterface<Child> 是否能被赋值给 IInterface<Parent>

被in修饰的泛型在接口中只能用于输入参数,是逆变的。例如我有父类和子类:

public class Parent { } public class Child : Parent { }

然后我定义了一个in修饰的泛型接口:

public interface IContravariant<in T> { 
    void getInput(T input); 
    //T getout(); // 这种会报错, in 类型的T只可以用于输入 
}

如果T标识成in,那么它只能用于输入,否则会报错。

然后我定义一个实现此接口的类:

public class class1<T> : IContravariant<T> {
   public void getInput(T input) { } 
}

那么接下来,得益于in的担保,我们可以确保一个 class1<Parent> 会把Parent类型用在参数输入而不是其它方面(似乎想起这样的话:给我买个手机吧,我保证用于学习而不是其他方面...)。那么对于一个class1<Parent>的实例类,当我们使用接口的Child泛型方法去调用时,总会传给他Child类型的参数,而它本身的参数是接收Parent类型的,肯定没毛病。

IContravariant<Child> v1 = new class1<Parent>();
//ITestInterface<Parent> v2 = new myClass<Child>(); // 会报错,不允许类型转换

对于out修饰的协变泛型,情况类似:

public interface ICovariant<out T> {
   T getOut(); 
    //void testInput(T input); //这种会报错,out类型的T只允许用于返回值
} 

public class class2<T> : ICovariant<T> where T : new() 
{ 
    //这里用where约束是因为我需要用 new 来返回一个T类型
    public T getOut() { return new T(); } 
}

得益于out的担保,T一定会应用于返回值而不是别的。那么对于一个class2<Child>的类,我们使用接口的Parent泛型方法去调用时,接收Parent类型的返回值,而这个实例类实际返回Child类型的方法,也保证了没有毛病。

//ICovariant<Child> v3 = new class2<Parent>(); // 会报错,不允许类型转换
ICovariant<Parent> v4 = new class2<Child>();

如果实在还不理解就这么记忆吧:

  • 协变,很外向(out修饰)很和谐,子类无伤转换为父类,非常和谐。
  • 逆变,很内向(in)很拧巴,父类别扭地转换为子类。

好吧,祝大家都外向一些,你看程序代码都这么设计了。天意,简直是天意!!

同时,注意 in 和 out 参数只可以用来定义泛型接口或者委托类型参数。

转载请注明出处。如果您觉得本文有用,欢迎点赞。
更多教程请在网易云课堂B站优酷腾讯视频搜索黑山老雕。

相关文章

  • C# 中泛型接口的协变和逆变(抗变)

    在C#中声明泛型接口时,我们可以使用 in 和 out 参数来控制这个泛型是协变还是逆变的,这里逆变有时也被翻译成...

  • Scala 通俗易懂 ---- 协变、逆变、不变

    协变、逆变、不变 Scala 语言中协变、逆变、不变是指拥有泛型的类型,在声明和赋值时的对应关系 协变:声明时泛型...

  • 泛型编程中的型变

    在泛型编程中,经常会提到型变。型变分为两种:协变与逆变。协变covariant表示与泛型参数T的变化相同,而逆变c...

  • Kotlin学习笔记 - 泛型

    1. 基本用法 2. 型变 型变包括 协变、逆变、不变 三种: 协变:泛型类型与实参的继承关系相同 逆变:泛型类型...

  • Scala 泛型协变与泛型边界

    代码准备 泛型协变 泛型协变、逆变、不变是指拥有泛型的类在声明和赋值时的对应关系。 协变:声明时泛型是父类,赋值时...

  • Typescript 中的协变和逆变

    Typescript的协变和逆变和C# Scala中的类似,但是Typescript的会自动算出来接口属于协变还是...

  • 协变和逆变

    Java的泛型只有通配符?和extends、super,没有语法上的协变和逆变。 什么是协变和逆变? 在混合OO和...

  • JAVA泛型与类型安全

    1. 基础泛型 2. 协变与逆变与不变 协变 简单来说即: Java中的数组是协变的 逆变与协变相对,逆转了类型关...

  • Java中的桥接方法与泛型的逆变和协变

    泛型的协变和逆变是什么?对应于Java当中,协变对应的就是,而逆变对应的就是

  • Java 泛型与通配符

    参考地址:《Java 泛型,你了解类型擦除吗?》 《Java中的逆变与协变》 《java 泛型中 T、E .....

网友评论

      本文标题:C# 中泛型接口的协变和逆变(抗变)

      本文链接:https://www.haomeiwen.com/subject/rhejectx.html