C#泛型基础

C# 泛型是一种强大的编程特性,允许开发者编写可重用、类型安全且高效的代码。通过泛型,可以在定义类、接口、方法或委托时使用类型参数,实际使用时再指定具体类型。以下是关于 C# 泛型的详细介绍:


泛型的核心优势

类型安全

泛型在编译时检查类型,避免运行时类型转换错误(如 object 的装箱拆箱操作)。

代码复用

同一套逻辑可适用于多种数据类型,无需为不同类型重复编写代码。

性能优化

避免值类型的装箱拆箱操作,提升性能(例如使用 List<int> 而非 ArrayList)。


泛型的基本用法

泛型类(Generic Class)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class GenericRepository<T>
{
    private List<T> _items = new List<T>();

    public void Add(T item) => _items.Add(item);
    public T Get(int index) => _items[index];
}

// 使用示例
var intRepo = new GenericRepository<int>();
intRepo.Add(42);

var stringRepo = new GenericRepository<string>();
stringRepo.Add("Hello");

泛型接口(Generic Interface)

1
2
3
4
5
6
7
8
9
public interface IComparer<T>
{
    int Compare(T x, T y);
}

public class IntComparer : IComparer<int>
{
    public int Compare(int x, int y) => x.CompareTo(y);
}

泛型方法(Generic Method)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public static void Swap<T>(ref T a, ref T b)
{
    T temp = a;
    a = b;
    b = temp;
}

// 使用示例
int x = 1, y = 2;
Swap(ref x, ref y); // 编译器自动推断类型为 int

泛型委托(Generic Delegate)

1
2
3
4
5
public delegate T Processor<T>(T input);

// 使用示例
Processor<int> square = n => n * n;
int result = square(5); // 25

类型约束(Type Constraints)

通过 where 关键字限制泛型参数的类型范围,增强类型安全性。

约束类型示例说明
值类型where T : structT 必须是值类型(如 int
引用类型where T : classT 必须是引用类型(如 string
无参构造函数where T : new()T 必须有默认构造函数
基类约束where T : SomeBaseClassT 必须继承自指定基类
接口约束where T : ISomeInterfaceT 必须实现指定接口
组合约束where T : class, new()多条件约束

示例

1
2
3
4
public class Factory<T> where T : IAnimal, new()
{
    public T Create() => new T();
}

协变与逆变(Covariance & Contravariance)

允许在泛型类型中更灵活地处理继承关系,通过 out(协变)和 in(逆变)关键字实现。

协变(Covariance)

  • 用于返回值类型(out T)。
  • 允许将派生类型作为泛型参数传递给接受基类型的接口。
1
2
IEnumerable<Cat> cats = new List<Cat>();
IEnumerable<Animal> animals = cats; // 合法,因为 IEnumerable<out T>

逆变(Contravariance)

  • 用于参数类型(in T)。
  • 允许将基类型作为泛型参数传递给接受派生类型的接口。
1
2
3
Action<Animal> animalAction = a => a.Eat();
Action<Cat> catAction = animalAction; // 合法,因为 Action<in T>
catAction(new Cat()); // 执行 animalAction

泛型中的默认值

使用 default(T) 获取类型的默认值:

  • 引用类型:null
  • 值类型:0、false 等。
1
public T GetDefault<T>() => default(T);

泛型与集合

.NET 提供了丰富的泛型集合类,如:

  • List<T>:动态数组
  • Dictionary<TKey, TValue>:键值对
  • Queue<T>:先进先出队列
  • Stack<T>:后进先出栈

对比非泛型集合(如 ArrayList):

  • 泛型集合无需类型转换,直接操作具体类型。
  • 避免因错误类型导致的运行时异常。

高级主题

反射与泛型

通过反射动态创建泛型类型或方法:

1
2
3
Type openType = typeof(List<>);
Type closedType = openType.MakeGenericType(typeof(int));
List<int> intList = (List<int>)Activator.CreateInstance(closedType);

泛型类型推断

编译器根据参数自动推断类型:

1
2
var list = new List<int> { 1, 2, 3 };
var first = list.First(); // 推断返回类型为 int

静态成员行为

每个封闭泛型类型(如 MyClass<int>MyClass<string>)拥有独立的静态成员。


使用场景

  • 需要处理多种数据类型的通用算法(如排序、搜索)。
  • 构建可复用的库或框架(如 ORM 中的泛型 Repository)。
  • 实现设计模式(工厂模式、策略模式等)。

总结

C# 泛型通过类型参数化显著提升了代码的灵活性和安全性,是编写高效、可维护代码的重要工具。合理使用泛型约束、协变/逆变等特性,可以进一步优化设计,减少重复代码。

Licensed under CC BY-NC-SA 4.0
使用 Hugo 构建
主题 StackJimmy 设计