1. 泛型的优点

    1. 促进了类型安全
    2. 减小了发生InvaildCastException的几率
    3. 泛型成员使用值类型,不需要造成到object的装箱拆箱
    4. 缓解了代码膨胀的情况
    5. 性能提高:不需要从object转型,避免类型检查;不需要为值类型装箱
    6. 减少了内存消耗(不需要为值类型装箱,减少堆内存消耗)
    7. 可读性变强
    8. 对代码编辑器友好
  2. 避免在一个类型中实现同一个泛型接口的多个构造
  3. CIL类型系统不支持“元数可变”的泛型类型
  4. 类型约束
// 以下并非限定类型为结构体或者类类型
// 限定类型为值类型和引用类型
where T:struct
where T:class
  1. 构造器约束
    使用约束规定必须有默认构造器,不是所有对象都有公共的默认构造器

添加new()要求必须存在默认构造器

wherer T: NewClass<Tkey>,new()
// ...
NewClass nc = new NewClass();
  1. 约束继承

    1. 派生的泛型类型必须跟基类相同或者更强,才能继承该基类。
    2. 虚泛型方法重写的时候,需要和基类方法完全一样的约束,否则会破坏多态性,是不被允许的。且重写版本的类型约束是隐式继承的。
  2. 约束的限制

    1. 不支持操作符约束
    2. 不支持 OR 条件(where后面的条件必须同时支持)
    3. 不支持委托和枚举类型的约束
    4. 构造器约束只支持默认构造器

8.协变性和逆变性

1. 将一个较为具体的类型赋给一个较泛化的类型,他们不会类型兼容的,也就是说它们不是协变量
2. 使用out修饰符允许协变性
3. 使用in修饰符允许逆变性,指示编译器核实T从未在属性的get方法中出现,也没有作为方法的返回值使用
interface IReadOnly<out T>
{
    T First{get;}
    T Seconde{get;}
}
  1. 协变转换的限制

    1. 泛型接口和泛型委托才可以协变。泛型类和结构永远不是协变的
    2. 提供给“来源”和“目标”泛型类型的类型实参必须是引用类型,不能是值类型
    3. 接口和委托必须声明为支持协变,编译器必须验证协变所针对的类型确实只在“输出”位置
  2. 逆变转换的限制

    1. 自己有泛型接口和委托类型才可以逆变
    2. 发生变化的类型参数只能是引用类型,而且编译器必须验证接口对于逆变转换是安全的
    3. 接口可以对一个类型参数协变,对另一个逆变,但是很少见,除了委托类型。例如系列委托Func<A1,A2,...,R>,对R协变,对其他参数逆变
  3. 数组对不安全协变的支持
    避免不安全的数组协变,而是考虑将数组转换成只读接口IEnumerable<T>,以便通过协变转换来安全的转换
  4. 泛型可以定义方法/属性/字段/类/接口/委托
  5. TODO: 基于引用类型的泛型的实例化/协变性和逆变性