DryIoc:注册构造参数不同但实现相同的依赖集合并关联服务生命周期的问题
你的问题核心在于直接注册实例(RegisterInstance)会强制单例生命周期,而你需要让IClient实例的生命周期和SearchService完全绑定。DryIoc的UseParentReuse确实是正确的方向,但需要调整注册方式——不能提前实例化Client,而是要让容器负责创建并管理它们的生命周期。
正确的注册方式
我们需要通过工厂方法注册每个IClient,同时指定UseParentReuse来绑定到SearchService的生命周期。这样容器会在解析SearchService时,自动创建对应语言的Client实例,并且这些实例会和SearchService共享相同的生命周期(比如单例、作用域或瞬时)。
修改你的组合根代码如下:
// 先注册SearchService,指定它的生命周期(这里以单例为例,你可以换成Scoped/Transient) container.Register<ISearchService, SearchService>(Reuse.Singleton); foreach (var config in SearchClientConfigurations) { // 为每个语言配置注册一个IClient,使用工厂方法传入Language参数 container.Register<IClient>( // 定义工厂方法:创建Client实例,传入当前配置的Language Made.Of(() => new Client(Arg.Index<Language>(0)), args: new object[] { config.Language }), // 设置重用策略:跟随父级(也就是SearchService)的生命周期 setup: Setup.With(Reuse.UseParentReuse) ); }
为什么之前的方式无效?
你之前用RegisterInstance注册提前创建好的Client实例,DryIoc默认会将这些实例标记为单例(Reuse.Singleton)——无论SearchService的生命周期是什么,这些Client都会一直存在于容器中,无法跟随SearchService的生命周期变化。
而使用工厂方法注册后,容器会在每次解析SearchService时,根据注册的规则创建新的Client实例(如果SearchService是瞬时的),或者只创建一次(如果SearchService是单例/作用域的),完全和父服务的生命周期同步。
额外说明
- 如果你的
SearchService使用**作用域(Scoped)**生命周期,那么每个作用域内的SearchService会拥有一套独立的Client实例,作用域结束时这些实例会被一起回收。 UseParentReuse会确保在同一个父级(SearchService实例)中,同一个语言的Client只会被创建一次,不会重复实例化。- 这种方式完全符合DI容器的职责:由容器负责依赖的创建和生命周期管理,不需要手动注入工厂,保持代码的简洁性。
现在你再调用container.Resolve<ISearchService>(),SearchService收到的IReadOnlyList<IClient>中的每个实例,都会和SearchService拥有相同的生命周期了。
内容的提问来源于stack exchange,提问作者LittlePilgrim




