CLR via c#读书笔记八:泛型
1、定义泛型类型或方法时,为类型指定的任何变量(比如T)都称为类型参数。使用泛型类型或方法时指定的具体数据类型称为类型实参。
2、System.Collections.Concurrent命名空间提供了线程安全的泛型集合类。Microsoft建议使用泛型集合类,不建议使用非泛型集合类。
3、具有泛型类型参数的类型称为开放类型,CLR禁止构造开放类型的任何实例。这类似于CLR禁止构造接口类型的实例。代码引用泛型类型时可指定一组泛型类型实参。为所有类型参数都传递了实际的数据类型,类型就成为封闭类型。CLR允许构造封闭类型的实例。
4、每个封闭类型都有自己的静态字段。换言之,假如List<T>定义了任何静态字段,这些字段不会在一个List<DateTime>和一个List<String>之间共享;每个封闭类型对象都有自己的静态字段。
5、泛型类型定义静态构造器的目的是保证传递的类型实参满足特定条件。例如,我们可以向下面这样定义只能处理枚举类型的泛型类型:
internal sealed class GenericTypeThatRequiresAnEnum<T>{
static GenericTypeThatRequiresAnEnum(){
if(!typeof(T).IsEnum){
throw new ArgumentException("T must be an enumerated type");
}
}
}
CLR提供了名为约束的功能,可以更好的指定有效的类型参数。遗憾的是,约束无法将类型实参限制为“仅枚举类型”。正是因为这个原因,所以上例需要用静态构造器来保证类型是一个枚举类型。
6、泛型类型仍然是类型,所有能从其他任何类型派生。使用泛型类型指定类型实参时,实际是在CLR中定义一个新的类型对象,新的类型对象从泛型类型派生自的那个类型派生。
7、泛型类型同一性:C#允许使用简化的语法来引用泛型封闭类型,同时不会影响类型的相等性,类如:
using DateTimeList=System.Collections.Generic.List<System.DateTime>;
using指令实际定义的是名为DateTimeList的符号,代码编译时,编译器将代码中出现的所有DateTimeList替换成System.Collections.Generic.List<System.DateTime>。这样就允许开发人员使用简化的语法,同时不影响代码的实际含义。
8、CLR要为每种不同的方法/类型组合生成本机代码。这个现象称为代码爆炸。幸好,CLR内建了一些优化措施能缓解代码爆炸。首先,假如为特定的类型实参调用了一个方法,以后再用相同的类型实参调用这个方法,CLR只会为这个方法/组合编译一次代码,同一个AppDomain中能共享不同程序集编译的相同泛型类型。另一个优化,它认为所有引用类型实参都完全相同,所以代码能够共享。例如,CLR为List<String>的方法编译的代码可直接用于List<Stream>的方法,因为String和Stream均为引用类型。事实上,对于任何引用类型,都会使用相同的代码,CLR之所以能执行这个优化,是因为所有引用类型的实参和变量实际只是指向堆上对象的指针(32位系统上是32位指针,64位系统上是64位指针),而所有对象指针都以相同方式操纵。但是类型实参是值类型,CLR 就必须专门为那个值类型生成本机代码。因为值类型的大小不定。
9、泛型接口
10、泛型委托
CLR支持泛型委托,目的是保证任何类型的对象都能以类型安全的方式传给回调方法。此外,泛型委托允许值类型实例在传给回调方法时不进行任何装箱。
11、委托和接口的逆变和协变泛型类型实参
不变量(invariant)意味着泛型类型参数不能更改。
逆变量(contravariant)意味着泛型类型参数可以从一个类更改为它的某个派生类。在C#是用in关键字标记逆变量形式的泛型类型参数。逆变量泛型类型参数只出现在输入位置,比如作为方法的参数。
协变量(covariant)意味着泛型类型参数可以从一个类更改为它的某个基类。c#是用out关键字标记协变量形式的泛型类型参数。协变量泛型类型参数只能出现在输出位置,比如作为方法的返回类型。
12、泛型方法
CLR还允许方法指定它自己的类型参数。这些类型参数可以作为参数、返回值和局部变量的类型使用。
internal sealed class GenericType(T){
private T m_value;
public GenericType(T value){ m_value=value; }
public TOutput Converter<TOutput>(){
TOutput result=(TOutput)Convert.ChangeType(m_value,typeof(TOutput));
return result;//返回类型转换之后的结果
}
}
这个例子类型参数是T,方法定义了自己的类型参数TOutput。
13、可验证性和约束
约束
public static T Min<T>(T o1,T o2) where T:IComparable<T>{
if(o1.CompareTo(o2)<0) return o1;
return o2;
}
C#的where关键字告诉编译器,为T指定的任何类型都必须实现同类型(T)的泛型IComparable接口。
重写虚泛型方法时,重写的方法必须指定相同数量的类型参数,而且这些类型参数会继承在基类方法上指定的约束。事实上,根本就不允许为重写方法的类型参数指定任何约束。但类型参数的名称是可以改变的。
14、主要约束
类型参数可以指定零个或者一个主要约束。主要约束可以是代表非密封类的一个引用类型。不能指定一下特殊引用类型:System.Object,System.Array,System.Delegate,System.multicastDelegate,System.ValueType,System.Enum或者System.Void。
指定引用类型约束,相当于向编译器承诺:一个指定的类型实参要么是与约束类型相同的类型,要么是从约束类型派生的类型。
有两个特殊的主要约束:class和struct。其中,class约束向编译器承诺类型实参是引用类型。任何类型、接口类型、委托类型或者数组类型都满足这个约束。struct约束向编译器承诺类型实参是值类型。
15、所有值类型都隐式地有一个公共无参构造器。
16、次要约束
类型参数可以指定零个或者多个次要约束,次要约束代表接口类型。
还有一个次要约束成为类型参数约束,有时也称为裸类型约束。它允许一个泛型类型或方法规定:指定的类型实参要么是约束的类型,要么是约束的类型的派生类。
17、构造器约束
类型参数可指定零个或一个构造器约束,它向编译器承诺类型实参是实现了公共无参构造器的非抽象类型。
internal sealed class ConstructorConstraint<T> where T:new(){
public static T Factory(){
//允许,因为所有值类型都隐式有一个公共无参构造器。
//而如果指定的是引用类型,约束也要求它提供公共无参构造器
return New T();
}
}
CLR via c#读书笔记八:泛型的更多相关文章
- [Clr via C#读书笔记]Cp12泛型
Cp12泛型 Generic: 特点 源代码保护 类型安全 清晰代码 更佳性能 Framework中的泛型 System.Collections.Generic; 开放类型,封闭类型:每个封闭类型都有 ...
- 《CLR via C#》读书笔记 之 泛型
第十二章 泛型 2014-06-15 初始泛型 12.3 泛型基础结构 12.3.1 开放类型与封闭类型 12.3.2 泛型类型和继承 12.3.3 泛型类型同一性 12.3.4 代码爆炸 12.6 ...
- CLR via C# 读书笔记---常量、字段、方法和参数
常量 常量是值从不变化的符号.定义常量符号时,它的值必须能在编译时确定.确定后,编译器将唱两只保存在程序集元数据中.使用const关键字声明常量.由于常量值从不变化,所以常量总是被视为类型定义的一部分 ...
- CLR via C# 读书笔记-21.托管堆和垃圾回收
前言 近段时间工作需要用到了这块知识,遂加急补了一下基础,CLR中这一章节反复看了好多遍,得知一二,便记录下来,给自己做一个学习记录,也希望不对地方能够得到补充指点. 1,.托管代码和非托管代码的区别 ...
- CLR via c#读书笔记九:接口
1.接口对一组方法签名进行了统一命名.接口还能定义事件.无参属性和有参属性(C#的索引器). 2.c#禁止接口定义任何一种静态成员. 3.C#编译器要求将实现接口的方法标记为public.CLR要求将 ...
- CLR via #C读书笔记三:基元类型、引用类型和值类型
1.一些开发人员说应用程序在32位操作系统上运行,int代表32位整数:在64位操作系统上运行,int代表64位整数.这个说法是完全错误的.C#的int始终映射到System.Int32,所以不管在什 ...
- Effective Java 读书笔记之四 泛型
泛型的本质是参数化类型.只对编译器有效. 一.请不要在新代码中使用原生态类型 1.泛型类和接口统称为泛型,有一个对应的原生态类型. 2.原生类型的存在是为了移植兼容性. 3.无限制通配类型和原生态类型 ...
- Clr Via C#读书笔记---I/O限制的异步操作
widows如何执行I/O操作 构造调用一个FileStream对象打开一个磁盘文件-----FileStream.Read方法从文件中读取数据(此时线程从托管代码转为本地/用户模式代码)- ...
- Clr Via C#读书笔记---计算限制的异步操作
线程池基础 1,线程的创建和销毁是一个昂贵的操作,线程调度以及上下文切换耗费时间和内存资源. 2,线程池是一个线程集合,供应你的用程序使用. 3,每个CLR有一个自己的线程池,线程池由CLR控制的所有 ...
随机推荐
- 51nod 1832 先序遍历与后序遍历【二叉树+高精度】
题目链接:51nod 1832 先序遍历与后序遍历 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 对于给定的一个二叉树的先序遍历和后序遍历,输出有多少种满足条件的 ...
- 解析纯真IP地址库
一周以来,一直在做 IP地址库的解析.从调研到编码到优化,大概花了有七八天的时间.感觉很好玩.总结一下整个做的过程. 1.关于IP 地址库的解析方式 目前主要的解析方式有两种:通过API,或通过IP数 ...
- Linux修改权限命令chmod用法详解
Linux系统中的每个文件和目录都有访问许可权限,用它来确定谁可以通过何种方式对文件和目录进行访问和操作. 文件或目录的访问权限分为只读,只写和可执行三种.以文件为例,只读权限表示只允许读其内容,而禁 ...
- Dispatch groups 与任务同步
https://developer.apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingG ...
- js中array(数组).map
使用前 使用后 代码:
- 【题解】洛谷P4391 [BOI2009] Radio Transmission(KMP)
洛谷P4391:https://www.luogu.org/problemnew/show/P4391 思路 对于给定的字符串 运用KMP思想 设P[x]为前x个字符前缀和后缀相同的最长长度 则对于题 ...
- peripheralStateNotificationCB
/********************************************************************* * @fn peripheralStateNotifica ...
- 如何在运行jar指定使用的JDK
写一个.bat文件 例如在同文件夹下,新建一个run.bat文件 run.bat 的内容是如下: set JAVA_HOME=C:\jdk1.7.0_67set CLASSPATH=.;%JAVA_H ...
- 简单的反编译class文件并重新编译的方法
在没有.java源码的情况下,如果想修改一个.class文件.可以通过以下步骤实现: 修改前的class文件: 一.反编译.class文件成.java文件. 1.可以使用Java Decompiler ...
- 浅谈HTML5中canvas中的beginPath()和closePath()的重要性
beginPath的作用很简单,就是开始一段新的路径,但在使用canvas绘图的过程中却非常重要 先来看一小段代码: var ctx=document.getElementById("can ...