什么是泛型?
- 定义:泛型允许您在类、接口和方法中定义占位符,这些占位符在使用时可以指定为具体的类型。
- 作用:通过减少重复代码和提供更强的类型检查,提高了代码的可重用性和性能。
泛型的核心概念
1.泛型类
- 泛型类能够操作特定的数据类型,而不需要为每种数据类型写一个类。提高代码复用性。
using System;
using System.Collections.Generic;public class GenericContainer<T>
{private T item;// 设置泛型项的值public void SetItem(T value) {item = value;}// 获取泛型项的值public T GetItem(){return item;}
}
使用泛型类示例:
public static void Demo(){// 使用int类型var intContainer = new GenericContainer<int>();intContainer.SetItem(10);// 使用string类型var stringContainer = new GenericContainer<string>();stringContainer.SetItem("Hello");}
2.泛型方法
可以在非泛型类中定义泛型方法,允许该方法独立于其所在类的参数类型。
public class GenericMethods
{// ref关键字表示参数按引用传递public void Swap<T>(ref T a, ref T b){T temp = a;a = b;b = temp;}// 演示多个类型参数的泛型方法public TResult Convert<TInput, TResult>(TInput input) where TResult : new(){// 处理类型转换逻辑return new TResult();}
}
使用泛型方法的示例:
public static void Demo(){var methods = new GenericMethods();// 演示Swap方法int x = 10, y = 20;Console.WriteLine($"交换前: x = {x}, y = {y}");methods.Swap(ref x, ref y);Console.WriteLine($"交换后: x = {x}, y = {y}");string str1 = "Hello", str2 = "World";Console.WriteLine($"交换前: str1 = {str1}, str2 = {str2}");methods.Swap(ref str1, ref str2);Console.WriteLine($"交换后: str1 = {str1}, str2 = {str2}");// 演示Convert方法int number = 42;string result = methods.Convert<int, string>(number);Console.WriteLine($"转换结果: {result}");}
3.泛型接口
允许接口的方法和属性使用泛型类型参数。
public interface IRepository<T>
{void Add(T item);void Remove(T item);T GetById(int id);IEnumerable<T> GetAll();
}
使用示例:
public class User
{public int Id { get; set; }public string Name { get; set; }
}// 实现用户仓储类
public class UserRepository : IRepository<User>
{private List<User> users = new List<User>();public void Add(User item){users.Add(item);}public void Remove(User item){users.Remove(item);}public User GetById(int id){return users.FirstOrDefault(u => u.Id == id);}public IEnumerable<User> GetAll(){return users;}
}// 演示仓储接口的使用
public static void Demo()
{var userRepo = new UserRepository();// 添加用户userRepo.Add(new User { Id = 1, Name = "张三" });userRepo.Add(new User { Id = 2, Name = "李四" });// 获取所有用户var allUsers = userRepo.GetAll();foreach (var user in allUsers){Console.WriteLine($"用户ID: {user.Id}, 名称: {user.Name}");}// 根据ID获取用户var user1 = userRepo.GetById(1);Console.WriteLine($"查找到用户: {user1?.Name}");// 删除用户userRepo.Remove(user1);
}
高级主题
约束
限制泛型参数的类型以增加灵活性和安全性。
- where T : struct:T必须是值类型。
- where T : class:T必须是引用类型。
- where T : new():T必须有一个无参构造函数。
- where T : BaseClass:T必须继承自BaseClass。
- where T : InterfaceName:T必须实现某接口。
public class Example<T> where T : new()
{public T CreateInstance(){return new T();}
}public class GenericConstraints
{public T Sum<T>(T a, T b) where T : struct
}
泛型委托
泛型不仅适用于类和方法,还可以用于委托。
public delegate T Transformer<T>(T arg);class Program
{static int Square(int x) => x * x;static void Main(){Transformer<int> transformer = Square;Console.WriteLine(transformer(3)); // 输出:9}
}
使用场景
1.集合类
- List<T>, Dictionary<TKey,TValue>, Queue<T>等都是泛型类的例子,可存储任何类型数据。
2.算法实现
- 可以创建通用的排序、搜索或其他算法,适用于任何类型。
3.类型安全事件处理
- 泛型委托用于事件系统中,确保类型匹配并提高安全性。
实践习题
1.创建一个泛型栈类GenericStack<T>,实现基本的栈操作:Push、Pop和Peek。
using System;
using System.Collections.Generic;public class GenericStack<T>
{private List<T> elements = new List<T>();// 将元素添加到栈顶的Push操作public void Push(T item){elements.Add(item);}// 移除并返回栈顶元素的Pop操作public T Pop(){if (elements.Count == 0){throw new InvalidOperationException("The stack is empty.");}T item = elements[^1]; // ^1 是C# 8.0语法,用于访问最后一个元素elements.RemoveAt(elements.Count - 1);return item;}// 返回栈顶元素但不移除的Peek操作public T Peek(){if (elements.Count == 0){throw new InvalidOperationException("The stack is empty.");}return elements[^1];}
}public class Program
{public static void Main(){GenericStack<int> stack = new GenericStack<int>();stack.Push(10);stack.Push(20);stack.Push(30);Console.WriteLine(stack.Peek()); // 输出:30Console.WriteLine(stack.Pop()); // 输出:30Console.WriteLine(stack.Pop()); // 输出:20}
}
2.编写一个泛型类LimitedType<T>,仅允许实现了IDisposable接口的类型作为参数,并包含一个释放资源的方法。
using System;public class LimitedType<T> where T : IDisposable, new()
{private T resource;public LimitedType(){resource = new T();}public void UseResource(){Console.WriteLine($"Using resource of type {typeof(T).Name}");// 假装使用资源}public void ReleaseResource(){Console.WriteLine($"Releasing resource of type {typeof(T).Name}");resource.Dispose();}
}public class MyResource : IDisposable
{public void Dispose(){Console.WriteLine("MyResource disposed");}
}public class Program
{public static void Main(){LimitedType<MyResource> limitedResource = new LimitedType<MyResource>();limitedResource.UseResource();limitedResource.ReleaseResource();}
}
说明:
- LimitedType类使用where T : IDisposable, new()约束,这意味着T必须实现IDisposable接口,并且具有无参构造函数。
- UseResource模拟使用资源,而ReleaseResource负责正确地释放资源。
- MyResource类实现了IDisposable接口,用于演示如何正确地处置资源。
通过这些例子,我们展示了如何利用泛型提高代码的通用性和灵活性。如果有任何问题或需要进一步讲解,请随时告诉我!