c# 高级编程 5章100页 【泛型】

141 阅读3分钟

泛型

  • 是C#编程语言的一种结构
  • 与IL紧密集成
  • 也是CLR定义的,因此可以跨编程语言
  • 可用于:
    • 接口
    • 方法
    • 委托
  • 作用: 避免编写,功能相同的方法和类,只创建一个方法或类,即可
    • 作为对比,Object似乎也能做到这一点,但这不是类型安全
    • 用泛型保证了类型安全性,如果某个类不支持泛型类编译器就会出现错误

后面将介绍:

通过泛型类,可以创建独立于类型的类

泛型方法,是独立于类型的方法

泛型委托,可以解耦出,方法中对集合所施加的算法

泛型方法的重载,允许在独立于类型的类里,如何为不同的类型实现不同的算法

泛型的优缺点

从以下5方面介绍优缺点

  • 性能
  • 类型安全性
  • 二进制代码重用
  • 代码的扩展
  • 命名约定

性能

ArrayList这个非泛型类和List<T>这个泛型类,为例:

装箱:从值类型转换成引用类型。拆箱:装箱的值类型,转换成值类型。拆箱,要用类型强制转换运算符。

ArrayList

ArrayList存储的每一个元素,都是对象,所以有以下拆装箱过程。

var list = new ArrayList();
list.Add(44); //装箱,把值类型转换成引用类型
int i1 = (int)list[0]  //拆箱,把引用类型转换成值类型
foreach(int i2 in list)
{
    Console.WriteLine(i2); //拆箱
}

拆装箱很容易,但是性能损失较大,遍历很多项时,性能损失尤其大。

List<T>

List<T>,若希望Tint:

  • JIT编译器会动态生成一个类
  • 这个类的每个元素就是int, 而不是对象
  • 因此不需要拆装箱
var list = new List<int>(); 
list.Add(44);  //不装箱,list里存储的就是int类型
int i1 = list[0];   //不拆箱,也无需做类型转换
foreach(int i2 in list)
{
    Console.WriteLine(i2);
}

类型安全

ArrayList这个非泛型类和List<T>这个泛型类,为例:

  • ArrayList能添加任意类型作为其元素
    • 而通过拆箱来使用元素的时候,需要强制类型转换
    • 转换无法实现的时候,就会报出运行时错误
    • 这无法在编译时报错
  • List<T> 只能添加T类型作为其元素
    • 如果试图添加其他无法转换为T的类型,会在编译时报错

二进制代码重用

  • 泛型类,定义一次,可用多种类型实例化
  • 泛型类,在一种语言中定义,在任何其他.NET语言中使用

实例化泛型时,创建多少代码

//源码
var list1  = new List<int>()
var list2 = new List<string>()

C#编译器编译源码产生程序集,程序集里的IL代码

  • 尚且不会List<T>复制代码,来代表实例化过的泛型类 JIT编译器IL代码,编译为本地代码
  • 此时会为值类型,创建新类,例如为List<int>创建新类
  • 不会为引用类型,创建新类,而是共享同一个本地类的所有相同的代码实现 原因如下:

实例化泛型类所需的内存引用类型只需要4个字节的内存地址,而每个值类型对内存的要求都不同

命名规则

  • 没有特殊要求,用字母T
  • 有特殊要求,以字母T作为前缀,使用描述性的名称。特殊要求,例如:
    • 必须实现一个接口
    • 必须派生自一个基类
    • 多个泛型类型
public class SortedList<TKey, TValue> { }

public delegate TOutput Converter<TInput, TOutput>(TInput from);

public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);