Skip to content

C# 泛型

本章将详细介绍 C# 中的泛型,包括泛型类、泛型方法、泛型接口、约束等概念,帮助你编写类型安全、高性能且可重用的代码。

泛型的基本概念

什么是泛型

csharp
// 泛型允许在定义类、接口、方法时使用类型参数
// 在使用时指定具体的类型,实现类型安全和代码重用

// 非泛型版本 - 需要为每种类型创建不同的类
public class IntStack
{
    private int[] items;
    private int count;
    
    public IntStack(int capacity = 10)
    {
        items = new int[capacity];
        count = 0;
    }
    
    public void Push(int item)
    {
        if (count >= items.Length)
            throw new InvalidOperationException("栈已满");
        items[count++] = item;
    }
    
    public int Pop()
    {
        if (count == 0)
            throw new InvalidOperationException("栈为空");
        return items[--count];
    }
    
    public int Count => count;
}

public class StringStack
{
    private string[] items;
    private int count;
    
    public StringStack(int capacity = 10)
    {
        items = new string[capacity];
        count = 0;
    }
    
    public void Push(string item)
    {
        if (count >= items.Length)
            throw new InvalidOperationException("栈已满");
        items[count++] = item;
    }
    
    public string Pop()
    {
        if (count == 0)
            throw new InvalidOperationException("栈为空");
        return items[--count];
    }
    
    public int Count => count;
}

// 泛型版本 - 一个类支持所有类型
public class Stack<T>
{
    private T[] items;
    private int count;
    
    public Stack(int capacity = 10)
    {
        items = new T[capacity];
        count = 0;
    }
    
    public void Push(T item)
    {
        if (count >= items.Length)
        {
            // 自动扩容
            Array.Resize(ref items, items.Length * 2);
        }
        items[count++] = item;
    }
    
    public T Pop()
    {
        if (count == 0)
            throw new InvalidOperationException("栈为空");
        return items[--count];
    }
    
    public T Peek()
    {
        if (count == 0)
            throw new InvalidOperationException("栈为空");
        return items[count - 1];
    }
    
    public bool IsEmpty => count == 0;
    public int Count => count;
    
    public void Clear()
    {
        Array.Clear(items, 0, count);
        count = 0;
    }
    
    public T[] ToArray()
    {
        T[] result = new T[count];
        Array.Copy(items, result, count);
        Array.Reverse(result);  // 栈是后进先出
        return result;
    }
}

static void BasicGenericDemo()
{
    Console.WriteLine("=== 基本泛型演示 ===");
    
    // 使用泛型栈
    Stack<int> intStack = new Stack<int>();
    Stack<string> stringStack = new Stack<string>();
    Stack<DateTime> dateStack = new Stack<DateTime>();
    
    // 整数栈操作
    Console.WriteLine("整数栈操作:");
    intStack.Push(10);
    intStack.Push(20);
    intStack.Push(30);
    
    Console.WriteLine($"栈顶元素: {intStack.Peek()}");
    Console.WriteLine($"栈大小: {intStack.Count}");
    
    while (!intStack.IsEmpty)
    {
        Console.WriteLine($"弹出: {intStack.Pop()}");
    }
    
    // 字符串栈操作
    Console.WriteLine("\n字符串栈操作:");
    stringStack.Push("First");
    stringStack.Push("Second");
    stringStack.Push("Third");
    
    string[] stringArray = stringStack.ToArray();
    Console.WriteLine($"栈内容: [{string.Join(", ", stringArray)}]");
    
    // 日期栈操作
    Console.WriteLine("\n日期栈操作:");
    dateStack.Push(DateTime.Now);
    dateStack.Push(DateTime.Now.AddDays(1));
    dateStack.Push(DateTime.Now.AddDays(2));
    
    Console.WriteLine($"最新日期: {dateStack.Pop():yyyy-MM-dd}");
}

泛型的优势

csharp
// 演示泛型的优势:类型安全、性能、代码重用

// 1. 类型安全
public class TypeSafetyDemo
{
    public static void CompareApproaches()
    {
        Console.WriteLine("=== 类型安全比较 ===");
        
        // 非泛型方式 - 使用 object
        ArrayList objectList = new ArrayList();
        objectList.Add(1);
        objectList.Add("Hello");
        objectList.Add(DateTime.Now);
        
        // 运行时错误风险
        try
        {
            int sum = 0;
            foreach (object item in objectList)
            {
                sum += (int)item;  // 运行时异常
            }
        }
        catch (InvalidCastException ex)
        {
            Console.WriteLine($"类型转换错误: {ex.Message}");
        }
        
        // 泛型方式 - 编译时类型检查
        List<int> intList = new List<int>();
        intList.Add(1);
        intList.Add(2);
        intList.Add(3);
        // intList.Add("Hello");  // 编译错误
        
        int sum = 0;
        foreach (int item in intList)
        {
            sum += item;  // 类型安全
        }
        Console.WriteLine($"安全计算结果: {sum}");
    }
}

// 2. 性能优势
public class PerformanceDemo
{
    public static void ComparePerformance()
    {
        Console.WriteLine("\n=== 性能比较 ===");
        
        const int iterations = 1000000;
        
        // 非泛型 - 装箱/拆箱开销
        var stopwatch = System.Diagnostics.Stopwatch.StartNew();
        ArrayList objectList = new ArrayList();
        for (int i = 0; i < iterations; i++)
        {
            objectList.Add(i);  // 装箱
        }
        
        int sum1 = 0;
        foreach (object item in objectList)
        {
            sum1 += (int)item;  // 拆箱
        }
        stopwatch.Stop();
        Console.WriteLine($"非泛型方式耗时: {stopwatch.ElapsedMilliseconds} ms");
        
        // 泛型 - 无装箱/拆箱
        stopwatch.Restart();
        List<int> intList = new List<int>();
        for (int i = 0; i < iterations; i++)
        {
            intList.Add(i);  // 无装箱
        }
        
        int sum2 = 0;
        foreach (int item in intList)
        {
            sum2 += item;  // 无拆箱
        }
        stopwatch.Stop();
        Console.WriteLine($"泛型方式耗时: {stopwatch.ElapsedMilliseconds} ms");
        
        Console.WriteLine($"结果验证: sum1={sum1}, sum2={sum2}");
    }
}

static void GenericAdvantagesDemo()
{
    TypeSafetyDemo.CompareApproaches();
    PerformanceDemo.ComparePerformance();
}

泛型类

基本泛型类

csharp
// 单类型参数泛型类
public class Pair<T>
{
    private T first;
    private T second;
    
    public Pair(T first, T second)
    {
        this.first = first;
        this.second = second;
    }
    
    public T First
    {
        get => first;
        set => first = value;
    }
    
    public T Second
    {
        get => second;
        set => second = value;
    }
    
    public void Swap()
    {
        T temp = first;
        first = second;
        second = temp;
    }
    
    public override string ToString()
    {
        return $"({first}, {second})";
    }
    
    public override bool Equals(object obj)
    {
        if (obj is Pair<T> other)
        {
            return EqualityComparer<T>.Default.Equals(first, other.first) &&
                   EqualityComparer<T>.Default.Equals(second, other.second);
        }
        return false;
    }
    
    public override int GetHashCode()
    {
        return HashCode.Combine(first, second);
    }
}

// 多类型参数泛型类
public class KeyValuePair<TKey, TValue>
{
    public TKey Key { get; }
    public TValue Value { get; set; }
    
    public KeyValuePair(TKey key, TValue value)
    {
        Key = key;
        Value = value;
    }
    
    public override string ToString()
    {
        return $"{Key}: {Value}";
    }
}

// 泛型集合类
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)
        {
            Resize();
        }
        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];
        }
        items[--count] = default(T);
    }
    
    public int IndexOf(T item)
    {
        return Array.IndexOf(items, item, 0, count);
    }
    
    public bool Contains(T item)
    {
        return IndexOf(item) >= 0;
    }
    
    public void Clear()
    {
        Array.Clear(items, 0, count);
        count = 0;
    }
    
    private void Resize()
    {
        capacity *= 2;
        Array.Resize(ref items, capacity);
    }
    
    public IEnumerator<T> GetEnumerator()
    {
        for (int i = 0; i < count; i++)
        {
            yield return items[i];
        }
    }
    
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

static void GenericClassDemo()
{
    Console.WriteLine("=== 泛型类演示 ===");
    
    // Pair 类演示
    Console.WriteLine("1. Pair 类:");
    Pair<int> intPair = new Pair<int>(10, 20);
    Console.WriteLine($"整数对: {intPair}");
    intPair.Swap();
    Console.WriteLine($"交换后: {intPair}");
    
    Pair<string> stringPair = new Pair<string>("Hello", "World");
    Console.WriteLine($"字符串对: {stringPair}");
    
    // KeyValuePair 类演示
    Console.WriteLine("\n2. KeyValuePair 类:");
    KeyValuePair<string, int> kvp1 = new KeyValuePair<string, int>("Age", 25);
    KeyValuePair<int, string> kvp2 = new KeyValuePair<int, string>(1, "First");
    Console.WriteLine($"KVP1: {kvp1}");
    Console.WriteLine($"KVP2: {kvp2}");
    
    // GenericList 类演示
    Console.WriteLine("\n3. GenericList 类:");
    GenericList<string> stringList = new GenericList<string>();
    stringList.Add("Apple");
    stringList.Add("Banana");
    stringList.Add("Cherry");
    
    Console.WriteLine($"列表内容: [{string.Join(", ", stringList)}]");
    Console.WriteLine($"包含 'Banana': {stringList.Contains("Banana")}");
    
    stringList.Remove("Banana");
    Console.WriteLine($"移除后: [{string.Join(", ", stringList)}]");
    
    // 索引器使用
    stringList[0] = "Apricot";
    Console.WriteLine($"修改后: [{string.Join(", ", stringList)}]");
}

泛型类的继承

csharp
// 泛型基类
public abstract class Repository<T>
{
    protected List<T> items;
    
    public Repository()
    {
        items = new List<T>();
    }
    
    public virtual void Add(T item)
    {
        items.Add(item);
        OnItemAdded(item);
    }
    
    public virtual bool Remove(T item)
    {
        bool removed = items.Remove(item);
        if (removed)
        {
            OnItemRemoved(item);
        }
        return removed;
    }
    
    public virtual T GetById(int id)
    {
        if (id >= 0 && id < items.Count)
            return items[id];
        return default(T);
    }
    
    public virtual IEnumerable<T> GetAll()
    {
        return items.AsReadOnly();
    }
    
    public int Count => items.Count;
    
    // 抽象方法 - 子类必须实现
    protected abstract void OnItemAdded(T item);
    protected abstract void OnItemRemoved(T item);
    
    // 虚方法 - 子类可以重写
    public virtual void Clear()
    {
        items.Clear();
        OnCleared();
    }
    
    protected virtual void OnCleared()
    {
        Console.WriteLine("仓储已清空");
    }
}

// 具体实现类
public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    
    public override string ToString()
    {
        return $"User(Id={Id}, Name={Name}, Email={Email})";
    }
}

public class UserRepository : Repository<User>
{
    private int nextId = 1;
    
    public override void Add(User user)
    {
        if (user.Id == 0)
        {
            user.Id = nextId++;
        }
        base.Add(user);
    }
    
    protected override void OnItemAdded(User user)
    {
        Console.WriteLine($"用户已添加: {user.Name} (ID: {user.Id})");
    }
    
    protected override void OnItemRemoved(User user)
    {
        Console.WriteLine($"用户已移除: {user.Name} (ID: {user.Id})");
    }
    
    public User GetByName(string name)
    {
        return items.FirstOrDefault(u => u.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
    }
    
    public IEnumerable<User> GetByEmailDomain(string domain)
    {
        return items.Where(u => u.Email.EndsWith($"@{domain}", StringComparison.OrdinalIgnoreCase));
    }
}

// 产品类和仓储
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    public int Stock { get; set; }
    
    public override string ToString()
    {
        return $"Product(Id={Id}, Name={Name}, Price={Price:C}, Stock={Stock})";
    }
}

public class ProductRepository : Repository<Product>
{
    private int nextId = 1;
    
    public override void Add(Product product)
    {
        if (product.Id == 0)
        {
            product.Id = nextId++;
        }
        base.Add(product);
    }
    
    protected override void OnItemAdded(Product product)
    {
        Console.WriteLine($"产品已添加: {product.Name} (库存: {product.Stock})");
    }
    
    protected override void OnItemRemoved(Product product)
    {
        Console.WriteLine($"产品已移除: {product.Name}");
    }
    
    public IEnumerable<Product> GetLowStockProducts(int threshold = 10)
    {
        return items.Where(p => p.Stock <= threshold);
    }
    
    public IEnumerable<Product> GetProductsByPriceRange(decimal minPrice, decimal maxPrice)
    {
        return items.Where(p => p.Price >= minPrice && p.Price <= maxPrice);
    }
    
    public void UpdateStock(int productId, int newStock)
    {
        var product = GetById(productId);
        if (product != null)
        {
            int oldStock = product.Stock;
            product.Stock = newStock;
            Console.WriteLine($"产品 {product.Name} 库存更新: {oldStock} -> {newStock}");
        }
    }
}

static void GenericInheritanceDemo()
{
    Console.WriteLine("=== 泛型继承演示 ===");
    
    // 用户仓储演示
    Console.WriteLine("1. 用户仓储:");
    UserRepository userRepo = new UserRepository();
    
    userRepo.Add(new User { Name = "Alice", Email = "alice@example.com" });
    userRepo.Add(new User { Name = "Bob", Email = "bob@company.com" });
    userRepo.Add(new User { Name = "Charlie", Email = "charlie@example.com" });
    
    Console.WriteLine($"总用户数: {userRepo.Count}");
    
    var alice = userRepo.GetByName("Alice");
    Console.WriteLine($"查找用户: {alice}");
    
    var exampleUsers = userRepo.GetByEmailDomain("example.com");
    Console.WriteLine($"example.com 域用户: {exampleUsers.Count()}个");
    
    // 产品仓储演示
    Console.WriteLine("\n2. 产品仓储:");
    ProductRepository productRepo = new ProductRepository();
    
    productRepo.Add(new Product { Name = "笔记本电脑", Price = 5999m, Stock = 15 });
    productRepo.Add(new Product { Name = "鼠标", Price = 99m, Stock = 5 });
    productRepo.Add(new Product { Name = "键盘", Price = 299m, Stock = 8 });
    
    Console.WriteLine($"总产品数: {productRepo.Count}");
    
    var lowStockProducts = productRepo.GetLowStockProducts();
    Console.WriteLine($"低库存产品: {lowStockProducts.Count()}个");
    foreach (var product in lowStockProducts)
    {
        Console.WriteLine($"  {product}");
    }
    
    var affordableProducts = productRepo.GetProductsByPriceRange(50m, 300m);
    Console.WriteLine($"价格在50-300元的产品: {affordableProducts.Count()}个");
    
    productRepo.UpdateStock(2, 20);  // 更新鼠标库存
}

泛型方法

基本泛型方法

csharp
public static class GenericMethods
{
    // 基本泛型方法
    public static void Swap<T>(ref T a, ref T b)
    {
        T temp = a;
        a = b;
        b = temp;
    }
    
    // 泛型方法重载
    public static T Max<T>(T a, T b) where T : IComparable<T>
    {
        return a.CompareTo(b) > 0 ? a : b;
    }
    
    public static T Max<T>(params T[] values) where T : IComparable<T>
    {
        if (values.Length == 0)
            throw new ArgumentException("至少需要一个值");
            
        T max = values[0];
        for (int i = 1; i < values.Length; i++)
        {
            if (values[i].CompareTo(max) > 0)
                max = values[i];
        }
        return max;
    }
    
    // 数组操作泛型方法
    public static T[] CreateArray<T>(int size, T defaultValue)
    {
        T[] array = new T[size];
        for (int i = 0; i < size; i++)
        {
            array[i] = defaultValue;
        }
        return array;
    }
    
    public static void PrintArray<T>(T[] array, string separator = ", ")
    {
        Console.WriteLine($"[{string.Join(separator, array)}]");
    }
    
    public static T[] FilterArray<T>(T[] array, Func<T, bool> predicate)
    {
        List<T> result = new List<T>();
        foreach (T item in array)
        {
            if (predicate(item))
            {
                result.Add(item);
            }
        }
        return result.ToArray();
    }
    
    // 转换方法
    public static TOutput[] ConvertArray<TInput, TOutput>(TInput[] input, Func<TInput, TOutput> converter)
    {
        TOutput[] output = new TOutput[input.Length];
        for (int i = 0; i < input.Length; i++)
        {
            output[i] = converter(input[i]);
        }
        return output;
    }
    
    // 查找方法
    public static int FindIndex<T>(T[] array, T item) where T : IEquatable<T>
    {
        for (int i = 0; i < array.Length; i++)
        {
            if (array[i].Equals(item))
                return i;
        }
        return -1;
    }
    
    public static bool Contains<T>(IEnumerable<T> collection, T item) where T : IEquatable<T>
    {
        foreach (T element in collection)
        {
            if (element.Equals(item))
                return true;
        }
        return false;
    }
    
    // 聚合方法
    public static TResult Aggregate<T, TResult>(IEnumerable<T> source, TResult seed, Func<TResult, T, TResult> func)
    {
        TResult result = seed;
        foreach (T item in source)
        {
            result = func(result, item);
        }
        return result;
    }
}

static void GenericMethodDemo()
{
    Console.WriteLine("=== 泛型方法演示 ===");
    
    // 交换演示
    Console.WriteLine("1. 交换方法:");
    int a = 10, b = 20;
    Console.WriteLine($"交换前: a={a}, b={b}");
    GenericMethods.Swap(ref a, ref b);
    Console.WriteLine($"交换后: a={a}, b={b}");
    
    string x = "Hello", y = "World";
    Console.WriteLine($"交换前: x={x}, y={y}");
    GenericMethods.Swap(ref x, ref y);
    Console.WriteLine($"交换后: x={x}, y={y}");
    
    // 最大值演示
    Console.WriteLine("\n2. 最大值方法:");
    Console.WriteLine($"Max(5, 10) = {GenericMethods.Max(5, 10)}");
    Console.WriteLine($"Max(3.14, 2.71) = {GenericMethods.Max(3.14, 2.71)}");
    Console.WriteLine($"Max('A', 'Z') = {GenericMethods.Max('A', 'Z')}");
    Console.WriteLine($"Max(1, 5, 3, 9, 2) = {GenericMethods.Max(1, 5, 3, 9, 2)}");
    
    // 数组操作演示
    Console.WriteLine("\n3. 数组操作:");
    int[] intArray = GenericMethods.CreateArray(5, 42);
    Console.Write("创建的数组: ");
    GenericMethods.PrintArray(intArray);
    
    string[] stringArray = { "apple", "banana", "cherry", "date", "elderberry" };
    Console.Write("字符串数组: ");
    GenericMethods.PrintArray(stringArray);
    
    // 过滤数组
    int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    int[] evenNumbers = GenericMethods.FilterArray(numbers, n => n % 2 == 0);
    Console.Write("偶数: ");
    GenericMethods.PrintArray(evenNumbers);
    
    // 转换数组
    string[] numberStrings = GenericMethods.ConvertArray(numbers, n => n.ToString());
    Console.Write("转换为字符串: ");
    GenericMethods.PrintArray(numberStrings);
    
    int[] stringLengths = GenericMethods.ConvertArray(stringArray, s => s.Length);
    Console.Write("字符串长度: ");
    GenericMethods.PrintArray(stringLengths);
    
    // 查找和聚合
    Console.WriteLine("\n4. 查找和聚合:");
    int index = GenericMethods.FindIndex(stringArray, "cherry");
    Console.WriteLine($"'cherry' 的索引: {index}");
    
    bool hasApple = GenericMethods.Contains(stringArray, "apple");
    Console.WriteLine($"包含 'apple': {hasApple}");
    
    int sum = GenericMethods.Aggregate(numbers, 0, (acc, n) => acc + n);
    Console.WriteLine($"数组求和: {sum}");
    
    string concatenated = GenericMethods.Aggregate(stringArray, "", (acc, s) => acc + s + " ");
    Console.WriteLine($"字符串连接: '{concatenated.Trim()}'");
}

泛型约束

基本约束类型

csharp
// 1. where T : class - 引用类型约束
public class ReferenceTypeContainer<T> where T : class
{
    private T item;
    
    public T Item
    {
        get => item;
        set => item = value;
    }
    
    public bool IsNull => item == null;
    
    public void SetToNull()
    {
        item = null;  // 只有引用类型可以设置为 null
    }
}

// 2. where T : struct - 值类型约束
public class ValueTypeContainer<T> where T : struct
{
    private T item;
    private bool hasValue;
    
    public ValueTypeContainer()
    {
        item = default(T);
        hasValue = false;
    }
    
    public T Item
    {
        get => hasValue ? item : throw new InvalidOperationException("没有值");
        set
        {
            item = value;
            hasValue = true;
        }
    }
    
    public bool HasValue => hasValue;
    
    public T GetValueOrDefault(T defaultValue = default(T))
    {
        return hasValue ? item : defaultValue;
    }
}

// 3. where T : new() - 无参构造函数约束
public class Factory<T> where T : new()
{
    public T CreateInstance()
    {
        return new T();  // 可以调用无参构造函数
    }
    
    public T[] CreateArray(int count)
    {
        T[] array = new T[count];
        for (int i = 0; i < count; i++)
        {
            array[i] = new T();
        }
        return array;
    }
}

// 4. where T : BaseClass - 基类约束
public abstract class Animal
{
    public string Name { get; set; }
    public abstract void MakeSound();
    
    public virtual void Sleep()
    {
        Console.WriteLine($"{Name} 正在睡觉");
    }
}

public class Dog : Animal
{
    public override void MakeSound()
    {
        Console.WriteLine($"{Name} 汪汪叫");
    }
}

public class Cat : Animal
{
    public override void MakeSound()
    {
        Console.WriteLine($"{Name} 喵喵叫");
    }
}

public class AnimalShelter<T> where T : Animal, new()
{
    private List<T> animals;
    
    public AnimalShelter()
    {
        animals = new List<T>();
    }
    
    public T AdoptAnimal(string name)
    {
        T animal = new T();
        animal.Name = name;
        animals.Add(animal);
        Console.WriteLine($"收养了 {typeof(T).Name}: {name}");
        return animal;
    }
    
    public void FeedAllAnimals()
    {
        Console.WriteLine("喂养所有动物:");
        foreach (T animal in animals)
        {
            animal.MakeSound();  // 可以调用基类方法
        }
    }
    
    public void NapTime()
    {
        Console.WriteLine("午睡时间:");
        foreach (T animal in animals)
        {
            animal.Sleep();
        }
    }
    
    public int Count => animals.Count;
}

// 5. where T : IInterface - 接口约束
public interface IComparable<T>
{
    int CompareTo(T other);
}

public interface IDrawable
{
    void Draw();
}

public class SortedList<T> where T : IComparable<T>
{
    private List<T> items;
    
    public SortedList()
    {
        items = new List<T>();
    }
    
    public void Add(T item)
    {
        int index = 0;
        while (index < items.Count && items[index].CompareTo(item) < 0)
        {
            index++;
        }
        items.Insert(index, item);
    }
    
    public T this[int index] => items[index];
    public int Count => items.Count;
    
    public IEnumerable<T> GetItems()
    {
        return items.AsReadOnly();
    }
}

// 6. 多重约束
public class DrawableFactory<T> where T : class, IDrawable, new()
{
    public T CreateAndDraw()
    {
        T item = new T();
        item.Draw();
        return item;
    }
    
    public void DrawAll(IEnumerable<T> items)
    {
        foreach (T item in items)
        {
            if (item != null)  // 引用类型约束允许 null 检查
            {
                item.Draw();
            }
        }
    }
}

// 示例可绘制类
public class Circle : IDrawable
{
    public void Draw()
    {
        Console.WriteLine("绘制圆形");
    }
}

public class Rectangle : IDrawable
{
    public void Draw()
    {
        Console.WriteLine("绘制矩形");
    }
}

static void GenericConstraintsDemo()
{
    Console.WriteLine("=== 泛型约束演示 ===");
    
    // 引用类型约束
    Console.WriteLine("1. 引用类型约束:");
    ReferenceTypeContainer<string> stringContainer = new ReferenceTypeContainer<string>();
    stringContainer.Item = "Hello";
    Console.WriteLine($"字符串容器: {stringContainer.Item}");
    stringContainer.SetToNull();
    Console.WriteLine($"设置为null后: {stringContainer.IsNull}");
    
    // 值类型约束
    Console.WriteLine("\n2. 值类型约束:");
    ValueTypeContainer<int> intContainer = new ValueTypeContainer<int>();
    Console.WriteLine($"初始状态有值: {intContainer.HasValue}");
    intContainer.Item = 42;
    Console.WriteLine($"设置值后: {intContainer.Item}");
    
    // 构造函数约束
    Console.WriteLine("\n3. 构造函数约束:");
    Factory<List<int>> listFactory = new Factory<List<int>>();
    List<int> newList = listFactory.CreateInstance();
    newList.AddRange(new[] { 1, 2, 3 });
    Console.WriteLine($"创建的列表: [{string.Join(", ", newList)}]");
    
    // 基类约束
    Console.WriteLine("\n4. 基类约束:");
    AnimalShelter<Dog> dogShelter = new AnimalShelter<Dog>();
    dogShelter.AdoptAnimal("旺财");
    dogShelter.AdoptAnimal("小黑");
    dogShelter.FeedAllAnimals();
    dogShelter.NapTime();
    
    // 接口约束
    Console.WriteLine("\n5. 接口约束:");
    SortedList<int> sortedInts = new SortedList<int>();
    sortedInts.Add(5);
    sortedInts.Add(2);
    sortedInts.Add(8);
    sortedInts.Add(1);
    Console.Write("排序列表: ");
    Console.WriteLine($"[{string.Join(", ", sortedInts.GetItems())}]");
    
    // 多重约束
    Console.WriteLine("\n6. 多重约束:");
    DrawableFactory<Circle> circleFactory = new DrawableFactory<Circle>();
    Circle circle = circleFactory.CreateAndDraw();
    
    DrawableFactory<Rectangle> rectangleFactory = new DrawableFactory<Rectangle>();
    Rectangle rectangle = rectangleFactory.CreateAndDraw();
}

本章小结

本章详细介绍了 C# 中的泛型:

关键要点:

  • 泛型定义:使用类型参数创建类型安全的通用代码
  • 泛型类:可以有一个或多个类型参数的类
  • 泛型方法:在方法级别定义类型参数
  • 泛型约束:限制类型参数必须满足的条件
  • 类型推断:编译器自动推断泛型方法的类型参数

泛型的优势:

  • 类型安全:编译时类型检查,避免运行时错误
  • 性能优化:避免装箱/拆箱操作
  • 代码重用:一套代码支持多种类型
  • IntelliSense支持:更好的开发体验

约束类型:

  • where T : class - 引用类型约束
  • where T : struct - 值类型约束
  • where T : new() - 无参构造函数约束
  • where T : BaseClass - 基类约束
  • where T : IInterface - 接口约束

最佳实践:

  • 使用有意义的类型参数名称(T, TKey, TValue等)
  • 合理使用约束提高类型安全性
  • 避免过度泛型化,保持代码可读性
  • 优先使用泛型集合而不是非泛型集合
  • 考虑协变和逆变(高级主题)

应用场景:

  • 集合类(List<T>, Dictionary<TKey,TValue>
  • 数据访问层(Repository<T>
  • 工厂模式(Factory<T>
  • 算法实现(排序、搜索等)

下一步: 在下一章中,我们将学习委托和事件,了解 C# 中的函数式编程特性。

延伸阅读

本站内容仅供学习和研究使用。