目录
为什么要有泛型
- 如果集合的类型指定的是object,那么在存储值类型的时候会有装箱的操作,C#默认会把值类型转换 为对应的引用类型。从集合中获取元素的时候,如果需要把引用类型转换为值类型就会有拆箱的操作。
- 如果方法的参数类型指定的是object,那么在调用该方法的时候,如果传入的参数是值类型,也会 有装箱的操作。在方法的内部需要把引用类型转换为值类型的时候也会有拆箱的操作。
- 而且在做类型强制转换的时候,如果类型的转换失败了,会抛出InvalidCastException异常。所以C#提 供了is和as操作符,用比较安全的方式来做类型的转换。
- 如果方法仅仅是参数的类型不同,但是内部的逻辑是一样的。比如就是输出一下方法入参的值,如果 用object就可能会有装箱和拆箱的操作,所以为了提高性能,可以把方法进行重载。写了很多方法, 只是参数的类型不同,但是内部的逻辑是一样的,这个时候就可以使用泛型,在同一个方法上操作多 种类型,进行代码的重用。
泛型是什么
- 泛型就是类型参数,是一个占位符,通过类型的参数化来实现在同一份代码上操作多种类型,达到代 码重用的目的。
- 泛型属于延迟声明。
- 泛型方法,泛型类,泛型接口,泛型委托,都是满足多个类型的需求。
泛型缓存
- 泛型缓存会根据传入的不同类型,分别生成不同的副本。
- 根据传入的不同类型,泛型类里面的静态构造函数会被执行多次。
泛型内部机制
泛型类型的”类型参数”会变成泛型类型的元数据,”运行时”在需要的时候会利用他们构造出合适的类型,通过这些类型,可以实例化不同的类型对象。
泛型约束
泛型约束可以保证程序的稳定性,在调用泛型方法时可以避免错误调用。
- where:struct 值类型,结构类型
- where:class 引用类型
- where:new() 存在无参公共构造函数
- where:接口名 某个接口的派生类型
泛型组合约束
- 泛型的组合约束不能既是引用类型又是值类型。
- 每一个引用类型都有一个构造函数,就不允许再指定一个构造函数进行约束。
- 在有多个转换类型时,其中一个为类,那么它应该出现在接口前面,不能多次指定同一个接口。
- 不同的类型参数可以有不同的约束,它们分别由一个where引入。
泛型的协变和逆变
- 在传统的OOP中,子类向上可以转换为父类,但是父类不能向下转换为子类。
- 比如Object obj = new Object(),然后string str = obj,编译器就会报错。
- 所以泛型通过逆变和协变来弥补这一缺陷。
Func委托的返回值只有协变
Action委托的输入参数只有逆变
out和in总结:
- out用来修饰输出参数,表示协变,一般用于委托或者方法的返回值,是子类到父类的变化。
- in用来修饰输入参数,表示逆变,一般用于委托或者方法的输入参数,是父类到子类的变化。
泛型的应用场景
- 封装一个深克隆的方法。
- 封装一个获取枚举描述信息的方法。
- 封装对象和XML相互转换的方法。
- 封装DataTable和List相互转换的方法。
- C#里面各种内置的扩展方法和各种内置的集合类型大部分都具有泛型版本。