《c#高级编程》第2章C#2.0中的更改(一)——泛型
一、实例
当我们需要编写一些通用的代码,但是不确定它们将处理的数据类型时,泛型就非常有用了。下面是一个简单的 C# 泛型示例:
using System; public class Example { public static void Main() { // 定义一个 int 数组 int[] ints = { 1, 2, 3, 4, 5 }; // 输出数组的所有元素 Console.WriteLine("Integers:"); PrintArray(ints); // 定义一个 string 数组 string[] strings = { "hello", "world", "!" }; // 输出数组的所有元素 Console.WriteLine("\nStrings:"); PrintArray(strings); } // 使用泛型方法输出数组的所有元素 public static void PrintArray<T>(T[] array) { foreach (T element in array) { Console.Write("{0} ", element); } Console.WriteLine(); } }
这个示例展示了泛型的核心思想 - 通过使用类型参数来实现通用性。使用泛型,我们可以编写一次性代码,以处理多种类型的数据,并且不必对每种数据类型都编写一份独立的代码。
总之,C# 泛型是一种非常强大的特性,它提高了代码的通用性和可重用性,同时避免了装箱和拆箱的性能损失。
二、基本原理
当我们定义一个泛型类或方法时,编译器会生成两个相关的实体 - 泛型类型和泛型方法。泛型类型用于描述包含类型参数的类型,而泛型方法则用于描述包含类型参数的方法。
在运行时,C# 的实现机制采用了类型擦除的策略。具体来说,在泛型类型和泛型方法被调用时,CLR(Common Language Runtime)会将其中的类型参数替换为实际的类型,并对其进行检查和转换操作。这个过程称为类型擦除。
例如,如果我们定义了以下泛型 List<T> 类:
```
class List<T>
{
private T[] array;
public List()
{
array = new T[10];
}
public void Add(T item)
{
// ...
}
}
```
那么在编译期间,编译器会生成一个非泛型类,它与上面的泛型类相似,但是使用 object 类型替换了 T 类型:
```
class List
{
private object[] array;
public List()
{
array = new object[10];
}
public void Add(object item)
{
// ...
}
}
```
当我们创建一个 List<int> 实例并调用 Add 方法时,CLR 会将类型参数 int 替换为实际的类型,并执行必要的类型检查和转换操作,然后执行相应的代码。
这个过程确保了泛型代码在运行时能够像普通代码一样执行,同时避免了代码重复。由于泛型类型和泛型方法只需要编译一次,因此它们在性能方面具有优势,并且不会占用额外的存储空间。
希望这个解释能够让你更好地理解 C# 泛型的实现过程。