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#读书笔记八:泛型的更多相关文章

  1. [Clr via C#读书笔记]Cp12泛型

    Cp12泛型 Generic: 特点 源代码保护 类型安全 清晰代码 更佳性能 Framework中的泛型 System.Collections.Generic; 开放类型,封闭类型:每个封闭类型都有 ...

  2. 《CLR via C#》读书笔记 之 泛型

    第十二章 泛型 2014-06-15 初始泛型 12.3 泛型基础结构 12.3.1 开放类型与封闭类型 12.3.2 泛型类型和继承 12.3.3 泛型类型同一性 12.3.4 代码爆炸 12.6 ...

  3. CLR via C# 读书笔记---常量、字段、方法和参数

    常量 常量是值从不变化的符号.定义常量符号时,它的值必须能在编译时确定.确定后,编译器将唱两只保存在程序集元数据中.使用const关键字声明常量.由于常量值从不变化,所以常量总是被视为类型定义的一部分 ...

  4. CLR via C# 读书笔记-21.托管堆和垃圾回收

    前言 近段时间工作需要用到了这块知识,遂加急补了一下基础,CLR中这一章节反复看了好多遍,得知一二,便记录下来,给自己做一个学习记录,也希望不对地方能够得到补充指点. 1,.托管代码和非托管代码的区别 ...

  5. CLR via c#读书笔记九:接口

    1.接口对一组方法签名进行了统一命名.接口还能定义事件.无参属性和有参属性(C#的索引器). 2.c#禁止接口定义任何一种静态成员. 3.C#编译器要求将实现接口的方法标记为public.CLR要求将 ...

  6. CLR via #C读书笔记三:基元类型、引用类型和值类型

    1.一些开发人员说应用程序在32位操作系统上运行,int代表32位整数:在64位操作系统上运行,int代表64位整数.这个说法是完全错误的.C#的int始终映射到System.Int32,所以不管在什 ...

  7. Effective Java 读书笔记之四 泛型

    泛型的本质是参数化类型.只对编译器有效. 一.请不要在新代码中使用原生态类型 1.泛型类和接口统称为泛型,有一个对应的原生态类型. 2.原生类型的存在是为了移植兼容性. 3.无限制通配类型和原生态类型 ...

  8. Clr Via C#读书笔记---I/O限制的异步操作

    widows如何执行I/O操作      构造调用一个FileStream对象打开一个磁盘文件-----FileStream.Read方法从文件中读取数据(此时线程从托管代码转为本地/用户模式代码)- ...

  9. Clr Via C#读书笔记---计算限制的异步操作

    线程池基础 1,线程的创建和销毁是一个昂贵的操作,线程调度以及上下文切换耗费时间和内存资源. 2,线程池是一个线程集合,供应你的用程序使用. 3,每个CLR有一个自己的线程池,线程池由CLR控制的所有 ...

随机推荐

  1. 最简单的PS渐变导入方法 photoshop渐变插件素材导入教程

    photoshop渐变插件素材可以让用户更好更直接,更快速地设计出自己想要的效果作品.网上有多种多样的ps渐变,那么Mac版Ps渐变怎么导入呢?这里我来和大家分享一下photoshop渐变插件素材导入 ...

  2. BZOJ 3744: Gty的妹子序列 【分块 + 树状数组 + 主席树】

    任意门:https://www.lydsy.com/JudgeOnline/problem.php?id=3744 3744: Gty的妹子序列 Time Limit: 20 Sec  Memory ...

  3. 16、SpringBoot-CRUD错误处理机制(3)

    3).将自己指定的数据携带出去 出现错误以后,会来到/error请求,会被BasicErrorController 进行处理 响应出去的数据是由 getErrorAttributes 得到的( Abs ...

  4. js 实现加入收藏/加入首页功能

    加入收藏夹实现: html代码如下: <a href="javascript:;" onclick="AddFavorite(window.location.hre ...

  5. ovs的卸载

    使用apt-get安装的openvswitch,然后卸载好麻烦撒,而且还没有相关资料说一下怎么删除的,特此记录一下,希望有个参考 首先把服务器上使用ovs新建的虚拟网桥全部删除掉 然后把原有的内核删除 ...

  6. AD9516锁相环功能外接环路滤波器的设计与分析

  7. localtunnel内网服务器暴露至公网

    摘自@scarlex   1.安装 npm install -g localtunnel 2.运行 lt --port 8080  (your url is: http://xxxx.localtun ...

  8. Python 学习笔记(十一)Python语句(一)

    运算符和条件语句 算术运算符 运算符 描述 实例 + 加 - 两个对象相加 a + b 输出结果 30 - 减 - 得到负数或是一个数减去另一个数 a - b 输出结果 -10 * 乘 - 两个数相乘 ...

  9. Java反射机制--是什么,为什么,怎么用。

    往往当我们面对一项新的知识时,我们往往需要知道三个方面,它是什么,它能做什么,它比原有知识强在哪里,我们该怎么使用它.当你能够解决这些问题时,便意味着你已经对这项知识入门了. 一.是什么 Java R ...

  10. es6 Set 和Map 数据结构

    ES6提供了新的数据结构Set,它类似于数组,但是成员的值都是唯一的,没有重复的值. Set 本身是一个数据结构,用来生成Set 数据结构. const s = new Set(); [2,3,5,4 ...