首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

了解C#的协变和逆变

前言 在引用类型系统时,协变、逆变和不变性具有如下定义。 这些示例假定一个名为 Base 的基类和一个名为 Derived的派生类。...以上来自于官方文档对协变、逆变、不变性的解释 为啥C#需要协变和逆变?...在C#中,目前只有泛型接口和泛型委托可以支持协变和逆变, 协变(Covariance) 内置的泛型协变接口,IEnumeratorT>、IQuerableT>、IGrouping的输入参数 当要进行类型转换,占位符T要转换的目标类型也必须是其子类,上述例子则是FooBase转为Foo 总结 协变和逆变只对泛型委托和泛型接口有效,对普通的泛型类和泛型方法无效 协变和逆变的类型必须是引用类型...,因为值类型不具备继承性,因此类型转换存在不兼容性 泛型接口和泛型委托可同时存在协变和逆变的类型参数,即占位符T 参考 泛型中的协变和逆变 | Microsoft Docs 《你必须知道的.NET(第2

94810
  • 您找到你想要的搜索结果了吗?
    是的
    没有找到

    Java泛型的协变和逆变

    背景 文接上回,说到过Java的泛型擦除问题,这块我又联想到一个有意思的考点泛型的协变和逆变。...一、协变 首先Java的数组是协变的,所以假设A是B的父类,那么A[]是可以保存A或者B的对象的,并且A[]是B[]的父类。 T>,写谁都会写,子类型限定。...super T>,超类型限定。 逆变同样也是在各类源码中层出不穷,结合协变的理解,这块相信大家应该不难理解。 常见的例子比如,List的继承关系, 假设存在继承关系Object-》T、T-》A、T-》B; 即T为A、B的父类,协变面向子类;逆变面向Object,它是所有对象的父类。...小结 1、协变、逆变的区别要分清 2、另外,再提一点泛型和通配符的区别,当然也可以结合第一点理解, T extends AAA>用于定义泛型类和方法,擦除后为AAA类型; <?

    72600

    c# 协变和逆变的理解

    泛型类型参数支持协变和逆变,可在分配和使用泛型类型方面提供更大的灵活性。 2....但是当我们将上述代码的子类和父类的位置调换,换成上述注释中的代码,编译器则会报错。...也正是因此,为了防止开发者写出错误的代码,.net 设计者便用了协变和逆变(对应 out 和 in 关键字)来强制要求正确行为。...所以归根到底,协变和逆变只是一种约束而已,这种规范限制了你的泛型接口中要么只能有将类型参数当作返回值的协变相容方法(加了 out 关键字),要么只能有将类型参数当作输入值的逆变相容方法(加了 in 关键字...本文针对的是对协变和逆变存在部分理解但是仍然有些迷糊的开发者群体,而笔者也忙于新技术的理解和投入使用,有段时间没能分享所学所得,这次也只是花了十几分钟撷取了重要概念记录答疑,希望能帮到一部分人,以上就是我的期望了

    1.5K60

    Java泛型的协变和逆变

    背景 文接上回,说到过Java的泛型擦除问题,这块我又联想到一个有意思的考点泛型的协变和逆变。...一、协变 首先Java的数组是协变的,所以假设A是B的父类,那么A[]是可以保存A或者B的对象的,并且A[]是B[]的父类。 T>,写谁都会写,子类型限定。...super T>,超类型限定。 逆变同样也是在各类源码中层出不穷,结合协变的理解,这块相信大家应该不难理解。 常见的例子比如,List的继承关系, 假设存在继承关系Object-》T、T-》A、T-》B; 即T为A、B的父类,协变面向子类;逆变面向Object,它是所有对象的父类。...小结 1、协变、逆变的区别要分清。 2、另外,再提一点泛型和通配符的区别,当然也可以结合第一点理解, T extends AAA>用于定义泛型类和方法,擦除后为AAA类型; <?

    54350

    C#4.0新增功能03 泛型中的协变和逆变

    泛型类型参数支持协变和逆变,可在分配和使用泛型类型方面提供更大的灵活性。 在引用类型系统时,协变、逆变和不变性具有如下定义。...对于接口,协变类型参数可用作接口的方法的返回类型,而逆变类型参数可用作接口的方法的参数类型。 协变和逆变统称为“变体” 。 未标记为协变或逆变的泛型类型参数称为“固定参数” 。...当代码需要派生程度较大的类型的比较器 (Shape) 时,该示例可以传递派生程度较小的类型的比较器 (Circle),因为 IComparerT> 泛型接口的类型参数是逆变参数。...泛型委托的类型参数中的协方差和逆变的效果类似于普通委托绑定中的协方差和逆变的效果(请参阅委托中的差异 (C#) 和委托中的差异 (Visual Basic))。...Visual Basic 和 C# 不允许违反协变和逆变类型参数的使用规则,也不允许将协变和逆变批注添加到接口和委托类型之外的类型参数中。

    1.3K20

    Effective Kotlin 译文:Chapter3-Item24-泛型的型变

    :out 和 in,其中 out 使得泛型协变,而 in 使得泛型逆变: class CupT> open class Dog class Puppy: Dog() fun main(args...box.set(42) // Int 也是 Any 子类,可以传入,离谱,我是狗窝,你给我塞一个 Int 因此,为了避免这种情况发生,Kotlin 在编译时禁止了这种行为:Kotlin 禁止在公有的输入位置使用协变的类型参数...Kotlin 中的 ListT>,在 Kotlin 中, List 只提供了可读方法,因此 List 在声明处定义成了协变(使用 out) 对应的,逆变的类型参数如果放在公有的输出位置,也会存在问题...因此,为了避免这种情况发生,Kotlin 在编译时禁止了这种行为:Kotlin 禁止在公有的输出位置使用逆变的类型参数: class BoxT> { var value: T?...在 Kotlin 中 List 和 Set 是协变的,MutableList,MutableSet,MutableMap 是不型变的 函数类型的参数类型是逆变的,函数类型的返回类型是协变的 协变的类型参数

    74840

    Effective Kotlin 译文:Chapter3-Item24-泛型的型变

    :out 和 in,其中 out 使得泛型协变,而 in 使得泛型逆变: class CupT> open class Dog class Puppy: Dog() fun main(args...box.set(42) // Int 也是 Any 子类,可以传入,离谱,我是狗窝,你给我塞一个 Int 因此,为了避免这种情况发生,Kotlin 在编译时禁止了这种行为:Kotlin 禁止在公有的输入位置使用协变的类型参数...Kotlin 中的 ListT>,在 Kotlin 中, List 只提供了可读方法,因此 List 在声明处定义成了协变(使用 out) 对应的,逆变的类型参数如果放在公有的输出位置,也会存在问题...因此,为了避免这种情况发生,Kotlin 在编译时禁止了这种行为:Kotlin 禁止在公有的输出位置使用逆变的类型参数: class BoxT> { var value: T?...在 Kotlin 中 List 和 Set 是协变的,MutableList,MutableSet,MutableMap 是不型变的 函数类型的参数类型是逆变的,函数类型的返回类型是协变的 协变的类型参数

    60910

    编码最佳实践——里氏替换原则

    Liskov替换原则的剩余原则都与协变和逆变相关。...首先要明确变体(variance)这个概念,变体这个术语主要应用于复杂层次类型结构中以定义子类型的期望类型,有点类似于多态。在C#语言中,变体的实现有协变和逆变两种。...EntityRepository和UserRepository两个类的父子继承关系也得以保留。 逆变 协变是与方法返回类型的处理有关,而逆变是与方法参数类型的处理有关。...这里的不变性是指“不会生成变体”。既不可协变也不可逆变,必定是个非变体。具体到实现层面,定义中没有对in和out关键字的引用,这二者分别用来指定逆变和协变。...C#语言的方法参数类型和返回类型都是不可变的,只有在设计泛型时才能将类型定义为可协变的或可逆变的。

    1.3K20

    协变、逆变与不变

    型变 型变(variance)是类型系统里的概念,包括协变(covariance)、逆变(contravariance)和不变(invariance)。...协变 在 Java 中,数组是协变的,也就是说,假设有一个基类 Person 和一个 Person 的子类 Student。...逆变 相对于协变,逆变显得非常不符合直觉,它表明,如果 B 是 A 的子类,那么 T[B] 反而是 T[A] 的父类。...语义与协变的情况是类似的。 于是,Scala 和 Java 的型变标记可以进行如下总结 3: Scala Java 解释 +T ?...在 Scala 中,如果进行了协变或者逆变的标记,编译器就会对这个类型参数的使用进行检查,如果它出现在了错误的位置上,编译器就会提示错误,防止了开发者因此而犯错。

    1.9K30

    Kotlin---泛型

    = null fun print() { println(a) } } 泛型的单继承关系 如果使用单继承关系的话,也和Java相同,在泛型定义时,使用继承即可 fun...而这极大的限制了程序的灵活性。于是就产生了协变与逆变。...super A>定义了逆变,允许向列表中添加以A为父类的B类对象,而不允许从列表中获取对象。 通过协变与逆变的方式,在保证代码灵活性的同时,也定义了代码的上下边界,保证代码的安全性。...Kotlin中的协变与逆变 前人总结过使用协变与逆变的时机,即:PECS。...而逆变可以允许objList中添加B对象,则可认为此时objList是作为Consumer来消费外部传入的数据。 而在Kotlin中使用out和in来实现协变与逆变。 首先定义三个类,递增继承。

    95830

    C#泛型的逆变协变之个人理解

    IFaceT> { public string Print(T input) => input.ToString(); } 这是一个逆变的例子, 与协变相似, 需要在泛型 T 之前加上关键词...in 对比上方的协变, 逆变看起来就像是将基类赋值给子类, 但这其实符合里氏代换的 当我们调用 item.Print 时, 看起来允许传入的参数为 string 类型, 而实际上最终调用的 Face逆变协变的限制 虽然上面讲了逆变(in)协变(out)看起来是什么样的, 但我的那个朋友还是有些疑问 Q:   那我什么时候可以用逆变, 什么时候可以用协变, 这两个东西用起来有什么限制?...A:   协变的表现形式为将子类赋值给基类, 当进行输出相关操作时, 输出的对象类型为基类, 是将子类转为基类, 你可以说子类是基类; 逆变的表现形式为将基类赋值给子类, 当进行输入相关操作时, 输入的对象为子类..., 是将子类转为基类, 这个时候你也可以说基类是子类; 如果同时支持逆变协变, 若先进行子类赋值给基类的操作, 此时输出的是基类, 子类转为基类并不会有什么问题, 但进行输入操作时就是在将基类转为子类,

    20120

    编程小知识之协变和逆变

    本文简述了 C# 中协变和逆变的一些知识 在 C# 中, 协变 和 逆变 能够实现 数组类型 和 委托类型 的隐式引用转换, .NET Framework 4 (包括)以后, C# 也开始支持在...泛型接口 和 泛型委托 中使用协变和逆变,下面的内容也主要围绕泛型类型参数的协变和逆变来进行讲解....小结: 协变和逆变用于隐式引用转换 协变的关键字为 out,被其修饰的参数类型只能用于输出参数 逆变的关键字为 in,被其修饰的参数类型只能用于输入参数 子类总是可以安全的转为父类是保证协变和逆变类型安全的统一前提...T>(Delegate1T> d1); 进一步的小结: 协变逆变需要根据具体情况分析,不能简单的参照输入参数及输出参数原则 输入参数及输出参数原则是依据参数本身而言的,不适用于参数的包装类型...参考资料 协变和逆变 (C#) 泛型中的协变和逆变 深入理解 C# 协变和逆变 理解 C# 泛型接口中的协变与逆变

    93830

    C#进阶-协变与逆变

    逆变协变可以用于泛型委托和泛型接口,本篇文章我们将讲解C#里逆变和协变的使用。逆变和协变的语法第一次接触难免感到陌生,最好的学习方式就是在项目中多去使用,相信会有很多感悟。...协变与逆变 协变(共变):泛型委托或泛型接口的类似于父类转向子类的变换; 逆变(反变):泛型委托或泛型接口的类似子类到父类的隐式转换; 逆变与协变用来描述类型转换后的继承关系,其定义:如果A、B表示类型...,f(x)表示类型转换,≤表示继承关系(比如,A≤B表示A是由B派生出来的子类) 当A≤B时,若f(x)是逆变的,则f(B)≤f(A)成立; 当A≤B时,若f(x)是协变的,则f(A)≤f(B)成立;...令List成为List子类的变化,我们叫做协变,和string与Object的父子关系是相同的;反之,令List成为List子类的变化,我们叫做逆变...,和string与Object的父子关系是相反的; 协变和逆变能够实现数组类型、委托类型和泛型类型参数的隐式引用转换。

    13721

    精读《Typescript infer 关键字》

    不就是多个变量指向同一个类型代词 E 嘛)同时接收到了 number 和 string,所以可以理解为 E 时而为 number 时而为 string,所以是或关系,这就是协变。...但这个例子也是同一个 U 时而为 string 时而为 number 呀,为什么是且的关系,而不是或呢? 其实协变或逆变与 infer 参数位置有关。...在 TypeScript 中,对象、类、数组和函数的返回值类型都是协变关系,而函数的参数类型是逆变关系,所以 infer 位置如果在函数参数上,就会遵循逆变原则。...逆变与协变: 协变(co-variant):类型收敛。 逆变(contra-variant):类型发散。...关于逆变与协变更深入的话题可以再开一篇文章了,这里就不细讲了,对于 infer 理解到这里就够啦。

    83040

    Android经典实战之用Kotlin泛型实现键值对缓存

    Kotlin 中的泛型是一种允许类型参数化的特性。它可以增强代码的重用性、类型安全性和可读性。在实际编写代码时,通过泛型,你可以编写更为通用的类和方法,而不必具体针对某种特定类型。...型变(Variance) Kotlin 中的型变分为协变(Covariance)和逆变(Contravariance)。协变允许子类型替换父类型,而逆变则相反。...协变 协变使用 out 关键字修饰类型参数。...value } } val producer: Producer = Producer(10) // 合法 逆变 逆变使用 in 关键字修饰类型参数。...通过以上的基础知识和实战示例,你可以更好地理解和应用泛型。 END 点赞转发,让精彩不停歇!关注我们,评论区见,一起期待下期的深度好文!

    9910
    领券