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. Intellij IDEA 代码中类非全路径显示

  2. BZOJ 1878 [SDOI2009]HH的项链 【莫队】

    任意门:https://www.lydsy.com/JudgeOnline/problem.php?id=1878 1878: [SDOI2009]HH的项链 Time Limit: 4 Sec  M ...

  3. Linux 学习总结(五)-linux 文件系统及相关命令

    一 linux文件系统概要 linux系统结构有别用于windos,他是树状结构的文件系统,在linux下我们称一切皆文件,我们将一个目录,可以成称为目录文件.linux只有一个单独的顶级目录结构.所 ...

  4. 记录一次Git问题及其解决方案

    错误信息:fatal: refusing to merge unrelated histories 错误产生背景:我将原先测试的项目本地删除后提交,然后将新的项目按照git的提交步骤进行提交,在最后一 ...

  5. stack的三个意思

    (转自阮一峰的网络日志,原网址http://www.ruanyifeng.com/blog/2013/11/stack.html) 阮一峰老师终于又更新博客了,个人认为这篇文章有一定科普意义,有一定解 ...

  6. 金融新手投标模块布局小Demo

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. Spring Boot集成Hazelcast实现集群与分布式内存缓存

    Hazelcast是Hazelcast公司开源的一款分布式内存数据库产品,提供弹性可扩展.高性能的分布式内存计算.并通过提供诸如Map,Queue,ExecutorService,Lock和JCach ...

  8. 『C++』Temp_2018_12_13 函数指针

    #include <iostream> #include <string> using namespace std; class Test{ private: string n ...

  9. 20181030NOIP模拟赛T3

    2017种树 2017共有N棵树从0到N-1标号.现要把这些树种在一条直线上,第i棵树的种植位置X[i]如下确定: X[0] = X[0] MOD L: X[i] = (X[i-1]*A+B) MOD ...

  10. 竞赛题解 - [CF 1080D]Olya and magical square

    Olya and magical square - 竞赛题解 借鉴了一下神犇tly的博客QwQ(还是打一下广告) 终于弄懂了 Codeforces 传送门 『题目』(直接上翻译了) 给一个边长为 \( ...