ASP.NET依赖注入:如何注册接口对应实现类型但不注册实例?
解决方案
方案1:手动维护接口-实现映射字典
该方案逻辑简单可控,不需要额外依赖,完全由你自主控制映射规则。
工厂类实现示例:
public class RepositoryFactory : IRepositoryFactory { // 存储接口类型到对应实现类型的映射关系 private static readonly Dictionary<Type, Type> _repositoryMappings = new(); private readonly IConnectionFactory _connectionFactory; public RepositoryFactory(IConnectionFactory connectionFactory) { _connectionFactory = connectionFactory; } // 提供映射注册方法,项目启动时统一调用 public static void RegisterMapping<TInterface, TImplementation>() where TInterface : IRepository where TImplementation : TInterface { _repositoryMappings[typeof(TInterface)] = typeof(TImplementation); } public TRepository Create<TRepository>(IUnitOfWork uow = null) where TRepository : IRepository { var interfaceType = typeof(TRepository); // 校验映射是否已注册 if (!_repositoryMappings.TryGetValue(interfaceType, out var implementationType)) { throw new InvalidOperationException($"未找到仓储接口 {interfaceType.Name} 对应的实现类映射"); } // 用实现类类型完成实例化 return (TRepository)Activator.CreateInstance(implementationType, uow, _connectionFactory); } }
在项目启动入口(Program.cs)完成映射注册:
// 批量注册所有仓储的接口-实现映射 RepositoryFactory.RegisterMapping<IItemRepository, ItemRepository>(); RepositoryFactory.RegisterMapping<IOrderRepository, OrderRepository>(); // 其他仓储依次注册即可 // 仅把工厂本身注入DI容器即可 builder.Services.AddSingleton<IRepositoryFactory, RepositoryFactory>();
你原有的仓储使用代码不需要做任何改动,完全符合预期的调用方式。
方案2:自动扫描生成映射
如果仓储数量较多,不想手动逐个注册,可以通过反射自动扫描程序集生成映射关系,省去手动注册的步骤:
在工厂类中添加自动注册方法:
public static void AutoRegisterMappings(Assembly implAssembly) { // 扫描程序集中所有实现了IRepository的非抽象类 var implTypes = implAssembly.GetTypes() .Where(t => t.IsClass && !t.IsAbstract && typeof(IRepository).IsAssignableFrom(t)); foreach (var implType in implTypes) { // 匹配实现类对应的仓储接口,可根据自己的命名规则调整匹配逻辑 var interfaceType = implType.GetInterfaces() .FirstOrDefault(i => i != typeof(IRepository) && typeof(IRepository).IsAssignableFrom(i)); if (interfaceType != null) { _repositoryMappings[interfaceType] = implType; } } }
启动时调用自动注册方法即可:
// 传入仓储实现类所在的程序集 RepositoryFactory.AutoRegisterMappings(typeof(ItemRepository).Assembly);
优化点:兼容不同构造函数参数规则
如果不同仓储的构造函数参数顺序不一致、或存在可选参数,可以优化实例化逻辑,按参数类型匹配传值,避免参数顺序错误导致的实例化失败:
public TRepository Create<TRepository>(IUnitOfWork uow = null) where TRepository : IRepository { var interfaceType = typeof(TRepository); if (!_repositoryMappings.TryGetValue(interfaceType, out var implType)) { throw new InvalidOperationException($"未找到仓储接口 {interfaceType.Name} 对应的实现类映射"); } // 取实现类的公共构造函数 var constructor = implType.GetConstructors().First(); // 按参数类型匹配传入对应值 var parameters = constructor.GetParameters().Select(p => { if (p.ParameterType == typeof(IUnitOfWork)) return uow; if (p.ParameterType == typeof(IConnectionFactory)) return _connectionFactory; // 其他固定参数可在此处补充匹配逻辑 return Type.Missing; }).ToArray(); return (TRepository)constructor.Invoke(parameters); }
该方案不需要在DI容器中注册任何仓储实例,仅需提前维护接口和实现类的映射关系,所有实例化逻辑完全由工厂自主控制。
内容的提问来源于stack exchange,提问作者wekso
相关产品推荐
相关产品推荐

