C#如何跨库边界在IServiceCollection中构建可扩展的服务集合
跨库向ServiceCollection注册共享集合对象的解决方案
核心思路
.NET 自带的依赖注入容器天然支持同一接口的多实现注册+自动聚合解析,不需要手动维护固定实例的集合,即可实现跨库扩展。
推荐方案:使用原生集合注入能力
这是最简洁、符合DI规范的实现方式,不需要额外封装:
- 库作者端注册逻辑:
不要直接注册写死实例的List<ICommand>,改为逐个注册你内置的ICommand实现:
// 库内注册代码 services.AddSingleton<ICommand, Command1>(); services.AddSingleton<ICommand, Command2>(); // 其他内置Command同理逐个注册
- 库内使用逻辑:
需要用到所有Command的位置,构造函数注入IEnumerable<ICommand>即可,DI会自动聚合所有注册过的ICommand实现(包括库外用户注册的),如果需要使用List类型直接转换即可:
public class YourCoreService { private readonly List<ICommand> _allCommands; public YourCoreService(IEnumerable<ICommand> commands) { _allCommands = commands.ToList(); } }
- 库使用者扩展逻辑:
用户只需要在自己的项目中注册自定义的ICommand实现,就会被自动纳入集合:
// 使用者端注册代码 services.AddSingleton<ICommand, UserCustomCommand>(); services.AddSingleton<ICommand, AnotherUserCommand>();
进阶方案:封装扩展方法做统一校验
如果你需要对用户注册的ICommand做统一校验、附加初始化逻辑,可以对外暴露扩展方法:
// 你库内对外提供的扩展方法 public static IServiceCollection AddCommand<TCommand>(this IServiceCollection services) where TCommand : class, ICommand { // 此处可添加自定义校验逻辑,比如检查实现是否符合要求、是否重复注册等 services.AddSingleton<ICommand, TCommand>(); return services; }
用户使用时直接调用扩展方法即可:
services.AddCommand<UserCustomCommand>();
特殊场景方案:必须共用同一个单例List实例
如果业务要求必须持有同一个全局List<ICommand>单例,可通过托管服务实现注入:
// 库内先注册空的单例List services.AddSingleton<List<ICommand>>(); // 注册Command的扩展方法 public static IServiceCollection AddCommand<TCommand>(this IServiceCollection services) where TCommand : class, ICommand { services.AddSingleton<TCommand>(); // 借助托管服务在服务启动时将实例添加到全局List services.AddHostedService(sp => { var globalList = sp.GetRequiredService<List<ICommand>>(); var commandInstance = sp.GetRequiredService<TCommand>(); globalList.Add(commandInstance); return EmptyHostedService.Instance; }); return services; } // 空托管服务占位实现 internal class EmptyHostedService : IHostedService { public static readonly EmptyHostedService Instance = new(); public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask; public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; }
内置Command和用户自定义Command都通过上述AddCommand扩展方法注册,即可全部添加到同一个单例List中。
通用逻辑总结:跨库构建共享对象的核心是避免直接硬编码构造固定实例注册,将构造权限开放给DI容器,通过逐个注册依赖项、由容器统一组合的方式实现无侵入式扩展,所有编译期可知的实现都可以适配这套逻辑。
内容的提问来源于stack exchange,提问作者Matt Newcomb
相关产品推荐
相关产品推荐

