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

C#高级语法之泛型、泛型约束,类型安全、逆变和协变(思想原理)

首先我们要明白,泛型是泛型,集合是集合,泛型集合就是带泛型的集合。...协变就是为了解决这一问题的,这样做其实也是为了解决类型安全问题(百度百科):例如类型安全代码不能从其他对象的私有字段读取值。它只从定义完善的允许方式访问类型才能读取。...逆变: ? 协变: ? 语法都是一些 非常粗糙的东西,重要的是思想、思想、思想。然后我们来看一下为什么要有逆变和协变? 什么叫做类型安全?...协变的话我相信应该很好理解,将子类转换为父类,兼容性好,解决了类型安全(因为子类转父类是肯定可以转换成功的);而协变作为返回值是百分百的类型安全 “逆变为什么又是解决了类型安全呢?子类转父类也安全吗?...所以当逆变作为参数传递时,类型是安全的。 思考:那么,现在你能明白上面那个错误,为什么“协变时泛型无法作为参数、逆变时泛型无法作为返回值”了吗?

7.1K30

编程小知识之协变和逆变

本文简述了 C# 中协变和逆变的一些知识 在 C# 中, 协变 和 逆变 能够实现 数组类型 和 委托类型 的隐式引用转换, .NET Framework 4 (包括)以后, C# 也开始支持在...什么是协变? 所谓协变(Covariance),是指能够使用比原始指定的类型派生程度更大的类型,简单理解就是 子类转为父类 这种变化....什么是逆变? 所谓逆变(Contravariance),是指能够使用比原始指定的类型派生程度更小的类型,简单理解就是 父类转为子类 这种变化....小结: 协变和逆变用于隐式引用转换 协变的关键字为 out,被其修饰的参数类型只能用于输出参数 逆变的关键字为 in,被其修饰的参数类型只能用于输入参数 子类总是可以安全的转为父类是保证协变和逆变类型安全的统一前提...参考资料 协变和逆变 (C#) 泛型中的协变和逆变 深入理解 C# 协变和逆变 理解 C# 泛型接口中的协变与逆变

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

    C#学习笔记七: C#4.0中微小改动-可选参数,泛型的可变性

    10 // 所以 IEnumerable泛型类型参数T支持协变性,所以可以 11 // 将List转化为IEnumerable(这个是继承的协变性支持的...// 这样下面这行代码就会出现编译错误,因为泛型的协变和逆变是C# 4.0 中新增加的特性,而.Net 4.0对应于C# 4.0。...类型. 2.3协变和逆变的注意事项 (1)只有接口和委托才支持协变和逆变, 类或泛型方法的类型参数都不支持协变和逆变 (2)协变和逆变只适用于引用类型, 值类型不支持协变和逆变(例如List无法转化为...当我们使用由dynamic关键字限制的变量时, 编译器并不知道它的类型, 该类型智能在程序运行时才能被确定. 动态类型的定义为: dynamic i = 5; 动态类型和静态类型到底有什么不同呢?...即obj = (int)obj + 10; 但是动态类型的引入到底有什么好处呢? 1,可以减少强制类型转换的使用.

    1.4K80

    Kotlin 泛型详解

    最近一段时间在网上发了一套 Kotlin 的入门视频,涵盖了基础语法、面向对象、高阶函数、DSL、协程等比较有特色的知识点,不过有朋友提出了疑问:这门课为什么不专门讲讲泛型、反射和注解呢?......     } } 为什么会报错呢?...对于协变的类型,通常我们是不允许将泛型类型作为传入参数的类型的,或者说,对于协变类型,我们通常是不允许其涉及泛型参数的部分被改变的。...这也很容易解释为什么 MutableCollection 是不变的,而 Collection 是协变的,因为在 Kotlin 当中,前者是可被修改的,后者是不可被修改的。...最后再给大家提一个点,现在你们知道为什么 in 表示逆变,out 表示协变了吗? 3. 通配符 在Java 中,当我们不知道泛型具体类型的时候可以用 ?

    1.2K20

    深入理解泛型

    extends E>: 在类型参数中使用 extends 表示这个泛型中的参数必须是 E 或者 E 的子类,这样有两个好处: 如果传入的类型不是 E 或者 E 的子类,编辑不成功。...extends T>; 如果它表示一个 T 的消费者,就使用 ; 如果既是生产又是消费,那使用通配符就没什么意义了,因为你需要的是精确的参数类型。...泛型的情况称为不可变性,与之对应的概念是协变、逆变: 协变:如果 A 是 B 的父类,并且 A 的容器(比如 List) 也是 B 的容器(List)的父类,则称之为协变的(父子关系保持一致...逆变:如果 A 是 B 的父类,但是 A 的容器 是 B 的容器的子类,则称之为逆变(放入容器就篡位了)。 不可变:不论 A B 有什么关系,A 的容器和 B 的容器都没有父子关系,称之为不可变。...Java 中数组是协变的,泛型是不可变的。   如果想要让某个泛型类具有协变性,就需要用到边界。 我们知道,泛型运行时被擦除成原始类型,这使得很多操作无法进行。

    46710

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

    object> list = new List(); 这个为什么就可以 A:   这就要讲到C#泛型里的逆变协变了 Q:   细嗦细嗦 逆变协变 C#泛型中的逆变(in)协变(out)对于不常自定义泛型的开发来说..., 帮助开发者更好地复用代码, 同时通过约束限制可能会出现的破坏类型安全的操作 逆变协变的限制 虽然上面讲了逆变(in)协变(out)看起来是什么样的, 但我的那个朋友还是有些疑问 Q:   那我什么时候可以用逆变..., 什么时候可以用协变, 这两个东西用起来有什么限制?...A:   简单来说, 有关泛型输入的用逆变, 关键词是in, 有关泛型输出的用协变, 关键词是out, 如果接口中既有输入又有输出, 就不能用逆变协变 Q:   为什么这两个不能同时存在?..., 是将子类转为基类, 这个时候你也可以说基类是子类; 如果同时支持逆变协变, 若先进行子类赋值给基类的操作, 此时输出的是基类, 子类转为基类并不会有什么问题, 但进行输入操作时就是在将基类转为子类,

    20120

    C#进阶-协变与逆变

    我们知道子类转换到父类,在C#中是能够隐式转换的。这种子类到父类的转换就是协变。而另外一种类似于父类转向子类的变换,可以简单的理解为逆变。...逆变协变可以用于泛型委托和泛型接口,本篇文章我们将讲解C#里逆变和协变的使用。逆变和协变的语法第一次接触难免感到陌生,最好的学习方式就是在项目中多去使用,相信会有很多感悟。...,f(x)表示类型转换,≤表示继承关系(比如,A≤B表示A是由B派生出来的子类) 当A≤B时,若f(x)是逆变的,则f(B)≤f(A)成立; 当A≤B时,若f(x)是协变的,则f(A)≤f(B)成立;...,和string与Object的父子关系是相反的; 协变和逆变能够实现数组类型、委托类型和泛型类型参数的隐式引用转换。...//数组-逆变 //数组的协变使派生程度更大的类型的数组能够隐式转换为派生程度更小的类型的数组。

    13721

    C#协变和逆变

    msdn 解释如下:  “协变”是指能够使用与原始指定的派生类型相比,派生程度更大的类型。  “逆变”则是指能够使用派生程度更小的类型。  解释的很正确,大致就是这样,不过不够直白。 ...上面是个人对协变和逆变的理解,比起记住那些派生,类型,原始指定,更大,更小之类的词语,个人认为要容易点。 ...正因如此,所以微软新增了两个关键字:Out,In,下面是他们的msdn解释: 协变的英文是:“covariant”,逆变的英文是:“Contravariant” 为什么Microsoft选择的是”Out...,反编译代码如下:  虽然通过了C#编译器的检查,但是il 并不知道协变和逆变,还是得乖乖的强制转换。 ...想要回答这个问题需要在回头看看Clr via C# 关于泛型和接口的章节了,我就不解释了,  答案是不可以。  上面演示的是协变,接下来要演示下逆变。

    95130

    Java魔法堂:解读基于Type Erasure的泛型

    JDK1.5引入了泛型、自动装箱拆箱等特性,C#到Java的过渡就流畅了不少。下面我们先重温两者非泛型和泛型的区别吧!...声明泛型变量,如 List lst = new ArrayList();      注意点——泛型不支持协变 // S为P的子类,但List并不是List的子类...,也就是不支持协变 // 因此下列语句无法通过编译 List lst = new ArrayList(); // 而数组支持协变 P[] array = new S[10];      ...say(msg);       一般情况下使用隐式指定实际类型的方式即可。   9. 使用泛型数组     只能使用通配符来创建泛型数组 List<?...IllegalAccessException e){} return ret; } }   而getP2中T被编译为Object,而clazz.newInstance()返回值类型为Object,那么为什么要加

    1K50

    Java魔法堂:解读基于Type Erasure的泛型

    JDK1.5引入了泛型、自动装箱拆箱等特性,C#到Java的过渡就流畅了不少。下面我们先重温两者非泛型和泛型的区别吧!...声明泛型变量,如 List lst = new ArrayList();      注意点——泛型不支持协变 // S为P的子类,但List并不是List的子类...,也就是不支持协变 // 因此下列语句无法通过编译 List lst = new ArrayList(); // 而数组支持协变 P[] array = new S[10];      ...say(msg);       一般情况下使用隐式指定实际类型的方式即可。   9. 使用泛型数组     只能使用通配符来创建泛型数组 List<?...IllegalAccessException e){} return ret; } }   而getP2中T被编译为Object,而clazz.newInstance()返回值类型为Object,那么为什么要加

    1.2K80

    金三银四面试:C#.NET面试题中高级篇3,含答案解析

    6.在.NET中的委托是什么? 7.在.NET中可以自定义委托吗? 8 .NET默认的委托类型有哪几种? 9.什么是泛型委托? 10. 什么是匿名方法?...当一个不正确的类型转换发生时,会产生InvalidCastException异常,有时我们会用try-catch块做一些尝试性的类型转换,这样的代码没有任何错误,但是性能却相当糟糕,为什么呢?...例如Func委托类型可以调用带返回类型且无参数的方法,Func委托类型调用带有4个参数和一个返回类型的方法。---->详解 9.什么是泛型委托?...(Object sender, TEventArgs e)where TEventArgs : EventArgs; 4).使用获取泛型实参和返回值的委托时,可利用逆变与协变。...逆变:父类转换为子类;协变:子类转换为父类 ---->详解 10. 什么是匿名方法? 匿名方法是用作委托的参数的一段代码。

    1.9K30

    Java泛型和通配符那点事

    这带来了很多好处:  · 类型安全。泛型的主要目标是提高 Java 程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。...泛型不是协变的  关于泛型的混淆,一个常见的来源就是假设它们像数组一样是协变的。其实它们不是协变的。List不是List的父类型。 ...invalid  最初,大多数 Java 程序员觉得这缺少协变很烦人,或者甚至是“坏的(broken)”,但是之所以这样有一个很好的原因。...>不是一个List(正如前一屏泛型不是协变的 中所学的)。...这就是为什么前一屏泛型方法 中的例子,允许List.get()在List上调用时返回Object,即使编译器不知道类型参数V的类型。

    1.6K50

    C# 学习笔记(15)—— C# 4.0

    ,这样编译器将判断参数的名称是否正确,然后将指定的值赋给对应的参数,从而达到只省略第二个参数的目的 泛型的可变性 在 C# 2.0 中,泛型并不具备可变形,这种可变形是指协变性和逆变性。...C# 2.0 确实是不支持的,但因为有了这样的需求,微软便适应地做出了改进,在 C# 4.0 中引入了泛型的协变性和逆变性 协变性 协变性指的是泛型类型参数可以从一个派生类隐式地转换为基类 C# 4.0...,派生类可以隐式转换为基类,反之则失败 逆变性 逆变性是指泛型类型参数可以从一个基类隐式地转换为派生类,C# 4.0 引入in关键字来标记泛型参数,以示其支持逆变性,下面以 .Net 类库中的接口public...并不是所有类型都支持泛型类型参数的协变和逆变性,下面总结了使用这两个特性时需要注意的地方 只有借口和委托才支持协变和逆变(如Func、Action),类或泛型方法的类型参数都不支持协变和逆变...协变和逆变只适用于引用类型,值类型不支持协变和逆变(因为可变性存在引用转换的过程,而值类型变量存储的就是对象本身,并不是对象的应用),所以List无法转换为IEnumerable<object

    25820

    协变、逆变与不变

    extends Person> persons 是 Java 的协变声明,它大概表达了这样的语义: List 的类型参数是 Person 的「某个」子类,而具体是什么类型并不知道,既然不知道是什么类型,...逆变 相对于协变,逆变显得非常不符合直觉,它表明,如果 B 是 A 的子类,那么 T[B] 反而是 T[A] 的父类。...,由此就能理解为什么函数类型相对于其参数的类型是逆变的了。...为什么数组是不变的?因为数组上的每个单元都相当于包含了两个方法,当写下 T value = arr[3] 这样的代码时,概念上可以理解为 T value = arr3.get()。...所以从给数组单元赋值这个操作上看,数组又在其元素的类型上逆变。因此,数组在其元素类型上不变。 为什么可以写 val person: Person = new Student 呢?

    1.9K30

    掌握 C# 语言中的泛型

    泛型常被誉为C#语言中最强大的特性之一,它使开发人员能够通过将类型指定推迟到运行时来创建灵活且高效的代码。在本文中,我们将通过实际场景来深入探究泛型的方方面面,助你成为泛型方面的高手。...为什么泛型很重要? 我们先来解答一个常被问到的问题:为什么要关注泛型呢? 泛型具有三个关键优势: 类型安全: 它们消除了强制类型转换的需求,并通过在编译时执行类型检查来防止代码出现运行时错误。...} } 场景2:用于灵活性和控制的泛型约束 C#泛型的一个强大特性是约束。...协变的实际应用: 协变在诸如从方法返回值之类的场景中很有用。...= dogs; // 由于协变,这是可行的 逆变的实际应用: 逆变在传递参数时很有用。

    6200

    C#11中的新语法

    C# 11 带来了许多新的语法特性和改进,以下是一些主要的新特性原始字符串文字:C# 11 引入了原始字符串文字,它允许你使用 """ 而不是 " 来定义字符串,这使得在字符串中包含引号、换行符和其他特殊字符时更为方便...2.文件范围的命名空间:在 C# 11 中,你可以使用 namespace 关键字在文件的顶部声明整个文件的命名空间,而不需要在每个类或结构体的顶部重复它。...namespace MyNamespace; class MyClass { // ... }3.必需成员:C# 11 引入了required关键字,用于指示接口或抽象类的成员在派生类或实现接口时必须是显式实现的...foreach (var number in GetOtherNumbersAsync()) { yield return number * 2; } }5.改进的协变返回类型...:C# 11 增强了协变返回类型的功能,允许在重写方法或实现接口时返回更具体的类型。

    18620

    不变(Invariant), 协变(Covarinat), 逆变(Contravariant) : 一个程序猿进化的故事

    阿袁在笔记上写下今天工作清单: 实现一个scala类ObjectHelper,带一个功能: 函数1:将一个对象转换成另一种类型的对象。 这个似乎是小菜一碟。...逆变(contravariant),可以理解为: 将一个对象转换成它的父类对象。 协变(coavariant),可以理解为: 将一个对象转换成它的子类对象。...C#的逆变,协变语法。...阿袁工作的第5天:协变、逆变的一个真正用途。 昨天的简洁方案,让阿袁认识到了自己还没有明白协变、逆变的真正用途。 它们到底有什么用呢?难道只是编译器自己玩的把戏吗?...的逆变 C#: out :协变 C#: in : 逆变 Level 3:理解协变和逆变发生的场景和用例 调用者对输入参数的协变用例 调用者对输出参数的逆变用例 调用者只有一个不平配的比较函数用例 //

    2.3K50

    C# 发展历史及版本新功能介绍

    到达迭代器方法的结尾时,循环便已完成。 协变和逆变 在 C# 中,协变和逆变能够实现数组类型、委托类型和泛型类型参数的隐式引用转换。 协变保留分配兼容性,逆变则与之相反。...以下代码演示分配兼容性、协变和逆变之间的差异。 // Assignment compatibility....Action actString = actObject; 数组的协变使派生程度更大的类型的数组能够隐式转换为派生程度更小的类型的数组。...泛型协变和逆变 协变和逆变都是术语,前者指能够使用比原始指定的派生类型的派生程度更大(更具体的)的类型,后者指能够使用比原始指定的派生类型的派生程度更小(不太具体的)的类型。...泛型类型参数支持协变和逆变,可在分配和使用泛型类型方面提供更大的灵活性。 在引用类型系统时,协变、逆变和不变性具有如下定义。

    4.2K20
    领券