C#基础提升系列——C# 泛型
C# 泛型(Generics)
泛型概述
泛型是C#编程语言的一部分,它与程序集中的IL(Intermediate Language,中间语言)代码紧密的集成。通过泛型,我们不必给不同的类型编写功能相同的许多方法和类,而是可以创建独立于被包含类型的一个类或方法。 例如,通过使用泛型类型参数 T,可以编写其他客户端代码能够使用的单个类,而不会产生运行时转换或装箱操作的成本或风险。使用泛型类型可以最大限度地重用代码、保护类型安全性以及提高性能。
泛型性能
泛型的一个主要优点是性能。值类型存储在栈上,引用类型存储在堆上。从值类型转换为引用类型称为装箱;从引用类型转换为值类型称为拆箱。对值类型使用非泛型集合类,常常需要将值类型和引用类型互相转换,进行装箱和拆箱操作,性能损失比较大。而使用了泛型,可以很好的解决这一问题,泛型可以不再进行装箱和拆箱操作。
泛型类型安全
泛型的另一个特性是类型安全。例如,在泛型类List<T>中,泛型类型T定义了允许使用的类型。假设有一个泛型实例为List<int>,它在添加元素时,就只会添加类型为int的数值到集合中。
泛型允许二进制代码重用
泛型允许更好的重用二进制代码,泛型类可以定义一次,使用许多不同的类型实例化。例如,泛型类List<T>可以实例化为List<int>、List<string>、List<MyClass>等。
泛型实例化时代码生成
泛型类的定义会放在程序集 中,所以用特定类型实例化泛型类不会在中间语言(IL)代码中复制这些类。但是,在JIT编译器把泛型类编译为本地代码时,会给每个值类型创建一个新类。而引用类型共享同一个本地类的所有相同的实现代码。这是因为引用类型在实例化泛型类中只需要4个字节的内存地址(32位系统),就可以引用一个引用类型。值类型包含在实例化的泛型类的内存中,同时因为每个值类型对内存的要求都不同,所以要为每个值类型实例化一个新类。
注:【本段文字来自于《C#高级编程(第10版)》中的”不同的特定类型实例化泛型时创建了多少代码“相关描述】
泛型类型命名约定
- 泛型类型的名称用字母
T作为前缀。 - 如果没有特殊的要求,泛型类型允许用任意类替代,且只使用了一个泛型类型,就可以用字符T作为泛型类型的名称。例如:
public class List<T>{} - 如果泛型类型有特定的要求(例如,它必须实现一个接口或派生自基类),或者使用了两个或多个泛型类型,就应给泛型类型使用描述性的 名称。例如:
public class SortedList<Tkey,TValue>{}
泛型类
泛型类型:也被称为泛型类型参数,它是在实例化泛型类的一个变量时,泛型声明中指定的特定类型的占位符,即泛型类中指定的T。
泛型类:定义泛型类型的类,例如List<T>,它无法按原样使用,因为它不是真正的类型;它更像是类型的蓝图。 若要使用 List<T>,客户端代码必须通过指定尖括号内的类型参数来声明并实例化构造类型。
创建泛型类
通常,创建泛型类是从现有具体类开始,然后每次逐个将类型更改为类型参数,直到泛化和可用性达到最佳平衡。 在创建泛型类之前,先建立一个简单的普通类,然后再把这个类转化为泛型类。
定义一个一般的、非泛型的简化链表类:
public class LinkedListNode
{
public object Value { get; private set; }
public LinkedListNode(object value)
{
Value = value;
}
public LinkedListNode Prev { get; internal set; }
public LinkedListNode Next { get; internal set; }
}
public class LinkedList : IEnumerable
{
public LinkedListNode First { get; private set; }
public LinkedListNode Last { get; private set; }
//在链表尾部添加一个新元素
public LinkedListNode AddLast(object node)
{
var newNode = new LinkedListNode(node);
if (First == null)
{
First = newNode;
Last = First;
}
else
{
LinkedListNode previous = Last;
Last.Next = newNode;
Last = newNode;
Last.Prev = previous;
}
return newNode;
}
//实现GetEnumerator()方法
public IEnumerator GetEnumerator()
{
LinkedListNode current = First;
while (