C# 中的泛型

155 阅读3分钟

C# 中的泛型(Generics)

在 C# 编程语言中,泛型(Generics)是一种强大的功能,它允许在定义类、接口、方法和委托时使用类型参数。泛型使代码更具通用性和重用性,并在编译时进行类型检查,从而提高了类型安全性和运行时性能。本文将详细介绍 C# 中的泛型及其各种用法。

泛型的主要特性

  1. 类型安全性:泛型在编译时进行类型检查,防止了类型转换错误,确保代码的安全性。
  2. 代码重用:泛型允许编写通用的代码,可用于处理不同的数据类型,显著提高代码的复用性。
  3. 性能优化:避免了装箱(boxing)和拆箱(unboxing)操作,特别是在处理值类型时,提升了性能。
  4. 类型参数约束:通过类型参数约束,可以限制泛型类型参数的类型,增强了灵活性和安全性。

一、泛型类

泛型类允许使用类型参数来定义类,这样同一个类可以处理不同的数据类型。

定义泛型类

public class GenericList<T>
{
    private T[] items;
    private int count;

    public GenericList(int capacity)
    {
        items = new T[capacity];
        count = 0;
    }

    public void Add(T item)
    {
        if (count < items.Length)
        {
            items[count] = item;
            count++;
        }
        else
        {
            throw new InvalidOperationException("List is full.");
        }
    }

    public T Get(int index)
    {
        if (index >= 0 && index < count)
        {
            return items[index];
        }
        else
        {
            throw new ArgumentOutOfRangeException("index");
        }
    }
}

使用泛型类

var intList = new GenericList<int>(5);
intList.Add(1);
intList.Add(2);

var stringList = new GenericList<string>(5);
stringList.Add("Hello");
stringList.Add("World");

二、泛型方法

泛型方法允许在方法级别使用类型参数,适用于需要处理不同类型的通用方法。

定义泛型方法

public class Utilities
{
    public T GetDefaultValue<T>()
    {
        return default(T);
    }
}

使用泛型方法

var utilities = new Utilities();
int defaultInt = utilities.GetDefaultValue<int>(); // 0
string defaultString = utilities.GetDefaultValue<string>(); // null

三、类型参数约束

类型参数约束允许对泛型类型参数施加条件,限制可用的类型,提高代码的安全性和灵活性。

常见的类型参数约束

  • where T : struct:T 必须是值类型。
  • where T : class:T 必须是引用类型。
  • where T : new():T 必须有一个无参数的构造函数。
  • where T : BaseClass:T 必须继承自 BaseClass。
  • where T : interfaceName:T 必须实现 interfaceName 接口。

示例

public class GenericClass<T> where T : IComparable
{
    public bool IsGreater(T a, T b)
    {
        return a.CompareTo(b) > 0;
    }
}

四、泛型接口

泛型接口允许定义具有通用类型参数的接口,适用于需要定义通用行为的场景。

定义泛型接口

public interface IRepository<T>
{
    void Add(T item);
    T Get(int id);
}

实现泛型接口

public class Repository<T> : IRepository<T>
{
    private List<T> items = new List<T>();

    public void Add(T item)
    {
        items.Add(item);
    }

    public T Get(int id)
    {
        return items[id];
    }
}

五、泛型委托

泛型委托允许定义通用的委托类型,可以处理不同类型的参数和返回值。

定义泛型委托

public delegate T Operation<T>(T a, T b);

public class MathOperations
{
    public T Add<T>(T a, T b)
    {
        return (dynamic)a + (dynamic)b;
    }
}

使用泛型委托

Operation<int> addOperation = new MathOperations().Add;
int result = addOperation(5, 3); // 8

六、常用的泛型集合类

.NET 提供了丰富的泛型集合类,它们在实际开发中非常常用。

常用泛型集合类

  • List<T>:动态数组。
  • Dictionary<TKey, TValue>:键值对集合。
  • Queue<T>:先进先出(FIFO)集合。
  • Stack<T>:后进先出(LIFO)集合。
  • HashSet<T>:无序集合,保证元素唯一。

使用 List<T>

var intList = new List<int> { 1, 2, 3, 4, 5 };
intList.Add(6);

foreach (var item in intList)
{
    Console.WriteLine(item);
}

总结

C# 中的泛型提供了类型安全性、代码重用和性能优化的优势。通过泛型类、泛型方法、泛型接口和泛型委托,开发者可以编写更通用、更灵活的代码。此外,类型参数约束进一步增强了泛型的实用性和安全性。在日常开发中,合理使用泛型可以显著提高代码质量和开发效率。无论是处理集合数据还是定义通用算法,泛型都是一种强大的工具。