如何通过反射批量注册带泛型接口的仓储服务
如何通过反射批量注册带泛型接口的仓储服务
兄弟,我太懂你这种手动注册几十个泛型仓储的痛苦了!每次加新仓储都要复制粘贴注册代码,完全是重复劳动,用反射批量注册绝对是解这个问题的最优解。我给你一步步拆解实现思路,还有现成的代码可以直接用。
首先明确我们的核心目标:从程序集里找出所有继承自泛型RepositoryBase<,>的仓储类(比如UserRepository<>),自动找到它们对应的泛型接口(比如IUserRepository<>),然后批量注册到DI容器中,以后不管加多少仓储,这一段代码就能搞定所有注册工作。
第一步:筛选出符合条件的仓储类
首先我们要从指定程序集里捞出来所有满足要求的仓储类:
- 必须是具体类(排除抽象类、接口)
- 必须继承自泛型的
RepositoryBase<,>(注意是泛型定义,不是某个具体的闭合泛型)
对应的代码是这样的:
// 先获取仓储所在的程序集,如果你仓储都在当前项目,就用GetExecutingAssembly var repositoryAssembly = Assembly.GetExecutingAssembly(); // 筛选出所有符合条件的仓储类 var repositoryClasses = repositoryAssembly.GetTypes() .Where(type => !type.IsAbstract && !type.IsInterface // 排除抽象类和接口 && type.BaseType != null // 确保有基类 && type.BaseType.IsGenericType // 基类是泛型 && type.BaseType.GetGenericTypeDefinition() == typeof(RepositoryBase<,>)) // 基类泛型定义是RepositoryBase<,> .ToList();
第二步:匹配仓储类对应的泛型接口
每个仓储类(比如UserRepository<>)都对应一个前缀加I的泛型接口(IUserRepository<>),我们要自动找到这个接口。这里的关键是利用类型名称的对应关系,同时确保找到的是泛型接口的定义。
遍历每个筛选出来的仓储类,做以下操作:
foreach (var repoClass in repositoryClasses) { // 先拿到仓储类的泛型定义(比如 UserRepository<> 而不是 UserRepository<某具体DbContext>) var repoGenericDefinition = repoClass.IsGenericType ? repoClass.GetGenericTypeDefinition() : repoClass; // 跳过非泛型的仓储类(如果有的话) if (!repoGenericDefinition.IsGenericTypeDefinition) { continue; } // 构造对应的接口名称:I + 仓储类泛型定义的名称(比如 UserRepository → IUserRepository) var targetInterfaceName = $"I{repoGenericDefinition.Name}"; // 从仓储类实现的所有接口里,找到匹配的泛型接口 var matchingInterface = repoClass.GetInterfaces() .FirstOrDefault(iface => iface.IsGenericType // 接口是泛型 && iface.GetGenericTypeDefinition().Name == targetInterfaceName); // 接口泛型定义名称匹配 // 找到接口后就注册到DI容器 if (matchingInterface != null) { // 注册开放泛型类型,DI容器会自动处理不同的DbContext泛型参数 services.AddScoped( matchingInterface.GetGenericTypeDefinition(), repoGenericDefinition); } }
第三步:验证和注意事项
- 命名规范要严格:这段代码依赖仓储类和接口的命名匹配(
XYZRepository<>对应IXYZRepository<>),如果有不符合这个规范的仓储,你可能需要单独处理,或者调整接口匹配的逻辑(比如通过自定义特性标记接口)。 - 程序集要选对:如果你的仓储类分散在不同的程序集里,要记得把这些程序集都获取到,再合并筛选。
- DI容器的自动处理:我们注册的是开放泛型类型(比如
IUserRepository<>和UserRepository<>),当你在代码里请求IUserRepository<DatabaseApiDbContext>或者IUserRepository<DatabaseApiDbContextSandbox>时,DI容器会自动创建对应的闭合泛型实例,完全不需要手动注册每个DbContext的版本。
这样一来,不管你以后加多少个仓储,只要遵循命名规范,这段代码就能自动完成所有注册工作,彻底告别手动复制粘贴的重复劳动!
备注:内容来源于stack exchange,提问作者Bruno
相关产品推荐
相关产品推荐

