C#之开放泛型和闭合泛型
在 .NET 中,“开放泛型(Open Generic)” 和 “闭合泛型(Closed Generic)” 是对泛型类型状态的两种描述,尤其常见于反射、依赖注入、插件框架等场景中。
🔍 一句话理解
- ✅ 开放泛型(Open Generic):定义了泛型参数,但还没有指定具体类型。
- ✅ 闭合泛型(Closed Generic):已经指定了所有泛型参数,成为一个完整的可用类型。
✅ 示例对比
类型表达式 | 类型状态 | 说明 |
---|---|---|
List<> | 开放泛型 | 定义了类型模板,还未指定元素类型 |
List<string> | 闭合泛型 | 指定了元素类型 string |
Dictionary<,> | 开放泛型 | 有两个未指定的类型参数 |
Dictionary<int, string> | 闭合泛型 | 所有参数都已指定 |
✅ 判断方式
Type t = typeof(List<>);
Console.WriteLine(t.IsGenericType); // true
Console.WriteLine(t.IsGenericTypeDefinition); // true ← 开放泛型
Type t2 = typeof(List<int>);
Console.WriteLine(t2.IsGenericType); // true
Console.WriteLine(t2.IsGenericTypeDefinition); // false ← 闭合泛型
✅ 在反射中的作用
✔ 判断类型是否实现某开放泛型接口:
Type type = typeof(MyRepository); // 假设实现了 IRepository<string>
Type openInterface = typeof(IRepository<>);bool implements = type.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == openInterface);
✔ 动态构造闭合泛型类型
Type openGeneric = typeof(List<>);
Type closed = openGeneric.MakeGenericType(typeof(string)); // List<string>
✅ 应用场景
场景 | 使用方式 |
---|---|
依赖注入容器(如 Autofac) | 支持注册开放泛型,如 IRepo<> |
插件系统 | 加载时匹配泛型接口实现 |
构建表达式树 / 动态代理 | 用开放泛型定义构建闭合类型 |
反射分析类型关系 | 区分模板类型和已绑定类型 |
✅ 小结对比
特性 | 开放泛型 | 闭合泛型 |
---|---|---|
是否具体可用 | ❌ 不能直接 new 或调用 | ✅ 可以直接使用 |
是否可构造实例 | 否 | 是 |
IsGenericType | ✅ 是 | ✅ 是 |
IsGenericTypeDefinition | ✅ 是 | ❌ 否 |
用途 | 模板定义、泛型比较、动态构造 | 实际使用 |
✅ 举个实战例子
假设你有一个服务接口 IHandler<T>
,多个实现:
public interface IHandler<T> {void Handle(T item);
}public class OrderHandler : IHandler<Order> { ... }
public class UserHandler : IHandler<User> { ... }
你想通过反射找出实现了 IHandler<>
的所有类型:
Type openGeneric = typeof(IHandler<>);var matches = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == openGeneric));