目录

第九章 泛型

9.1 泛型基础

为什么需要泛型

泛型允许我们编写类型安全、可重用的代码,而不需要在编译时确定具体类型。

// 不使用泛型 - 需要为每种类型写重复代码
public class IntStack
{
    private int[] items;
    public void Push(int item) { }
    public int Pop() => 0;
}
 
public class StringStack
{
    private string[] items;
    public void Push(string item) { }
    public string Pop() => null;
}
 
// 使用object - 类型不安全,需要装箱拆箱
public class ObjectStack
{
    private object[] items;
    public void Push(object item) { }
    public object Pop() => null;
}
 
// 使用泛型 - 类型安全,高性能,可重用
public class Stack<T>
{
    private T[] items;
    public void Push(T item) { }
    public T Pop() => default;
}

9.2 泛型类

定义泛型类

public class GenericClass<T>
{
    private T value;
 
    public GenericClass(T value)
    {
        this.value = value;
    }
 
    public T GetValue() => value;
 
    public void SetValue(T newValue) => value = newValue;
}
 
// 使用
var intClass = new GenericClass<int>(42);
var stringClass = new GenericClass<string>("Hello");

多类型参数

public class Pair<T1, T2>
{
    public T1 First { get; set; }
    public T2 Second { get; set; }
 
    public Pair(T1 first, T2 second)
    {
        First = first;
        Second = second;
    }
 
    public void Swap()
    {
        // 只有当T1和T2相同时才能交换
        // 需要使用约束或运行时检查
    }
 
    public override string ToString() => $"({First}, {Second})";
}
 
// 使用
var pair = new Pair<string, int>("Age", 25);
var swapped = new Pair<int, string>(25, "Age");

9.3 泛型方法

定义泛型方法

public class GenericMethods
{
    // 泛型方法
    public void Swap<T>(ref T a, ref T b)
    {
        T temp = a;
        a = b;
        b = temp;
    }
 
    // 返回泛型类型
    public T CreateInstance<T>() where T : new()
    {
        return new T();
    }
 
    // 泛型参数数组
    public void PrintAll<T>(params T[] items)
    {
        foreach (var item in items)
        {
            Console.WriteLine(item);
        }
    }
}
 
// 使用
var methods = new GenericMethods();
int x = 5, y = 10;
methods.Swap(ref x, ref y);
Console.WriteLine($"x={x}, y={y}");
 
methods.PrintAll("Hello", "World", "!");
methods.PrintAll(1, 2, 3, 4, 5);

类中定义泛型方法

public class Container<T>
{
    private T value;
 
    // 使用类的类型参数
    public void SetValue(T val) => value = val;
    public T GetValue() => value;
 
    // 泛型方法使用自己的类型参数
    public void Process<U>(U item)
    {
        Console.WriteLine($"Container类型: {typeof(T).Name}");
        Console.WriteLine($"Process类型: {typeof(U).Name}");
        Console.WriteLine($"值: {item}");
    }
 
    // 转换方法
    public Container<U> Transform<U>(Func<T, U> converter)
    {
        return new Container<U>(converter(value));
    }
 
    public Container(T value) => this.value = value;
}
 
// 使用
var container = new Container<int>(42);
container.Process("测试");  // T是int, U是string
var stringContainer = container.Transform(i => i.ToString());

9.4 泛型约束

约束类型

约束 语法 说明
——————
值类型 where T : struct T必须是值类型
引用类型 where T : class T必须是引用类型
无参构造函数 where T : new() T必须有无参构造函数
基类 where T : BaseClass T必须继承自BaseClass
接口 where T : IInterface T必须实现IInterface
可空 where T : notnull T必须是非空类型

约束示例

// 值类型约束
public class ValueTypeContainer<T> where T : struct
{
    public T Value { get; set; }
 
    public bool HasValue => true;  // 值类型总是有值
}
 
// 引用类型约束
public class ReferenceTypeContainer<T> where T : class
{
    private T value;
 
    public T Value
    {
        get => value;
        set => this.value = value ?? throw new ArgumentNullException();
    }
}
 
// 构造函数约束
public class Factory<T> where T : new()
{
    public T Create() => new T();
}
 
// 基类约束
public class AnimalContainer<T> where T : Animal
{
    public void MakeAllSounds(List<T> animals)
    {
        foreach (var animal in animals)
        {
            animal.MakeSound();
        }
    }
}
 
// 接口约束
public class Sorter<T> where T : IComparable<T>
{
    public void Sort(List<T> list)
    {
        list.Sort();
    }
}
 
// 多约束
public class MultiConstraint<T> where T : class, IComparable<T>, new()
{
    // T必须是引用类型
    // T必须实现IComparable<T>
    // T必须有无参构造函数
}

9.5 泛型接口

// 定义泛型接口
public interface IRepository<T> where T : class
{
    T GetById(int id);
    IEnumerable<T> GetAll();
    void Add(T entity);
    void Update(T entity);
    void Delete(int id);
}
 
// 实现泛型接口
public class InMemoryRepository<T> : IRepository<T> where T : class, new()
{
    private readonly List<T> items = new List<T>();
    private int nextId = 1;
 
    public T GetById(int id)
    {
        // 假设T有Id属性 - 实际实现可能使用反射或接口约束
        return items.FirstOrDefault();
    }
 
    public IEnumerable<T> GetAll() => items;
 
    public void Add(T entity)
    {
        items.Add(entity);
    }
 
    public void Update(T entity)
    {
        // 实现更新逻辑
    }
 
    public void Delete(int id)
    {
        // 实现删除逻辑
    }
}
 
// 使用
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}
 
var productRepo = new InMemoryRepository<Product>();
productRepo.Add(new Product { Name = "Laptop", Price = 999 });

9.6 泛型委托

// 定义泛型委托
public delegate TResult MyFunc<in T, out TResult>(T arg);
public delegate void MyAction<in T>(T arg);
public delegate bool MyPredicate<in T>(T obj);
 
// 使用自定义泛型委托
public class GenericDelegateDemo
{
    public static void Main()
    {
        // 使用自定义委托
        MyFunc<int, string> intToString = n => $"Number: {n}";
        MyAction<string> print = Console.WriteLine;
        MyPredicate<int> isPositive = n => n > 0;
 
        print(intToString(42));
        Console.WriteLine(isPositive(5));
 
        // 使用内置委托
        Func<int, int, int> add = (a, b) => a + b;
        Action<string> log = msg => Console.WriteLine($"[LOG] {msg}");
        Predicate<int> isEven = n => n % 2 == 0;
    }
}

9.7 泛型与继承

// 泛型基类
public class GenericBase<T>
{
    public T Value { get; set; }
}
 
// 继承并指定类型
public class IntDerived : GenericBase<int>
{
    public void Increment() => Value++;
}
 
// 保持泛型
public class GenericDerived<T> : GenericBase<T>
{
    public void Reset() => Value = default;
}
 
// 添加类型参数
public class MultiDerived<T, U> : GenericBase<T>
{
    public U ExtraValue { get; set; }
}
 
// 使用
var intDerived = new IntDerived { Value = 5 };
intDerived.Increment();
Console.WriteLine(intDerived.Value);  // 6

9.8 协变与逆变

协变(out)

// 协变:可以返回更具体的类型
public interface ICovariant<out T>
{
    T GetItem();
    // void SetItem(T item);  // 编译错误,不能入参
}
 
public class Covariant<T> : ICovariant<T>
{
    private T item;
 
    public Covariant(T item) => this.item = item;
 
    public T GetItem() => item;
}
 
// 使用协变
ICovariant<string> stringCovariant = new Covariant<string>("Hello");
ICovariant<object> objectCovariant = stringCovariant;  // 协变转换

逆变(in)

// 逆变:可以接受更一般的类型
public interface IContravariant<in T>
{
    void SetItem(T item);
    // T GetItem();  // 编译错误,不能出参
}
 
public class Contravariant<T> : IContravariant<T>
{
    private T item;
 
    public void SetItem(T item) => this.item = item;
}
 
// 使用逆变
IContravariant<object> objectContravariant = new Contravariant<object>();
IContravariant<string> stringContravariant = objectContravariant;  // 逆变转换

9.9 实战:泛型集合类

public class GenericList<T> : IEnumerable<T>
{
    private T[] items;
    private int count;
    private int capacity;
 
    public GenericList(int initialCapacity = 4)
    {
        capacity = initialCapacity;
        items = new T[capacity];
        count = 0;
    }
 
    public int Count => count;
    public int Capacity => capacity;
 
    public T this[int index]
    {
        get
        {
            if (index < 0 || index >= count)
                throw new IndexOutOfRangeException();
            return items[index];
        }
        set
        {
            if (index < 0 || index >= count)
                throw new IndexOutOfRangeException();
            items[index] = value;
        }
    }
 
    public void Add(T item)
    {
        if (count == capacity)
        {
            Grow();
        }
        items[count++] = item;
    }
 
    public bool Remove(T item)
    {
        int index = IndexOf(item);
        if (index >= 0)
        {
            RemoveAt(index);
            return true;
        }
        return false;
    }
 
    public void RemoveAt(int index)
    {
        if (index < 0 || index >= count)
            throw new IndexOutOfRangeException();
 
        for (int i = index; i < count - 1; i++)
        {
            items[i] = items[i + 1];
        }
        count--;
        items[count] = default;  // 清除引用
    }
 
    public int IndexOf(T item)
    {
        for (int i = 0; i < count; i++)
        {
            if (EqualityComparer<T>.Default.Equals(items[i], item))
                return i;
        }
        return -1;
    }
 
    public bool Contains(T item) => IndexOf(item) >= 0;
 
    public void Clear()
    {
        for (int i = 0; i < count; i++)
        {
            items[i] = default;
        }
        count = 0;
    }
 
    public void Sort() where T : IComparable<T>
    {
        Array.Sort(items, 0, count);
    }
 
    public void Sort(IComparer<T> comparer)
    {
        Array.Sort(items, 0, count, comparer);
    }
 
    private void Grow()
    {
        capacity *= 2;
        T[] newItems = new T[capacity];
        Array.Copy(items, newItems, count);
        items = newItems;
    }
 
    public IEnumerator<T> GetEnumerator()
    {
        for (int i = 0; i < count; i++)
        {
            yield return items[i];
        }
    }
 
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        => GetEnumerator();
}
 
// 使用
var list = new GenericList<int>();
list.Add(3);
list.Add(1);
list.Add(2);
list.Sort();
 
foreach (var item in list)
{
    Console.WriteLine(item);  // 1, 2, 3
}

练习题

基础练习

1. 泛型交换:编写一个泛型方法Swap<T>,交换两个变量的值。

2. 泛型查找:创建泛型方法FindFirst<T>,在数组中查找第一个匹配的元素。

3. 泛型容器:实现一个简单的GenericStack<T>类,支持Push、Pop、Peek操作。

进阶练习

4. 泛型缓存:设计GenericCache<TKey, TValue>类:

  1. 支持添加、获取、删除缓存项
  2. 支持过期时间
  3. 线程安全

5. 泛型比较器:实现泛型方法FindMax<T>,在集合中查找最大值,要求T实现IComparable<T>。

6. 泛型工厂:创建GenericFactory<T>,要求T必须有无参构造函数,支持对象池管理。

挑战练习

7. LINQ简化版:实现一组LINQ风格的扩展方法:

  1. Where<T>
  2. Select<T, TResult>
  3. OrderBy<T, TKey>
  4. FirstOrDefault<T>
  5. Any<T>

8. 依赖注入容器:实现简单的泛型DI容器:

  1. Register<TInterface, TImplementation>()
  2. RegisterInstance<T>(T instance)
  3. Resolve<T>()
  4. 支持单例和瞬态生命周期

本章小结

本章学习了C#泛型:

  1. 泛型类和泛型方法的定义
  2. 多类型参数
  3. 泛型约束的各种类型
  4. 泛型接口
  5. 泛型委托
  6. 泛型与继承
  7. 协变和逆变
  8. 完整的泛型集合实现

泛型是C#类型系统的核心特性,能够大大提高代码的复用性和类型安全性。