使用DI/IoC容器时如何处理对象销毁?以DryIoc为例
单例服务中按需创建并销毁含非托管资源服务的解决方案
问题描述
我正在使用DryIoc,但这是一个所有IoC容器通用的问题。假设有一个单例服务SingletonService,它每次调用方法时都需要一组新对象(这里简化为WorkerService),该服务使用非托管资源,因此必须确保销毁。
我不清楚如何确保WorkerService在不再需要时立即销毁。据我了解,在单例服务中持有容器引用属于服务定位器反模式,不可取。
我想到的一种解决方案是向SingletonService注入WorkerServiceFactory,该工厂通过注入获取容器,再用容器获取WorkerService并返回给SingletonService。但我不确定是否应由SingletonService负责销毁WorkerService?是否有准则指出容器创建的对象应由容器销毁?另外我也考虑使用作用域,但不确定如何实现:如果在SingletonService中创建新作用域,仍会持有容器引用(至少DryIoc中是如此);在工厂中创建作用域则意义不大,因为只有工厂能访问该作用域。
请问该如何处理这类场景?
补充实现方案
我进一步思考后提出了如下实现:
using DryIoc; using JetBrains.Annotations; using var container = new Container(); container.Register<ISingletonService, SingletonService>(reuse: Reuse.Singleton); container.Register<IWorkerService, WorkerService>(reuse: Reuse.Scoped); container.Register<IWorkerServiceFactory, WorkerServiceFactory>(reuse: Reuse.Singleton); var singleton = container.Resolve<ISingletonService>(); singleton.PrintData(); singleton.PrintData(); singleton.PrintData(); singleton.PrintData(); singleton.PrintData(); interface ISingletonService { void PrintData(); } class SingletonService(IWorkerServiceFactory workerFactory) : ISingletonService { public void PrintData() { using var scope = workerFactory.Create(out var worker); Console.WriteLine(worker.GetData()); } } interface IWorkerService { string GetData(); } class WorkerService : IWorkerService, IDisposable { public void Dispose() { Console.WriteLine("WorkerService was disposed"); } public string GetData() { return "Hello Data"; } } interface IWorkerServiceFactory { [MustDisposeResource] IDisposable Create(out IWorkerService service); } class WorkerServiceFactory(IResolverContext ctx) : IWorkerServiceFactory { public IDisposable Create(out IWorkerService service) { var scope = ctx.OpenScope(); service = scope.Resolve<IWorkerService>(); return scope; } }
本质上我通过out参数返回WorkerService,同时将工厂内创建的作用域返回给调用方。这样SingletonService只需销毁工厂返回的作用域,其余由容器处理。请问这是一种合理的方案吗?
方案分析与优化建议
你的方案是合理且符合IoC最佳实践的,核心思路解决了几个关键问题:
- 避免服务定位器反模式:单例服务仅依赖工厂接口,不直接持有容器引用
- 确保资源及时释放:通过返回作用域并让调用方用
using声明管理,销毁作用域时容器会自动处置该作用域内所有实现IDisposable的服务(包括WorkerService) - 遵循容器管理准则:容器创建的对象由容器负责销毁,这里通过作用域销毁触发容器清理逻辑,完全符合规范
可优化点
- 替换
out参数为元组返回:C# 7.0+支持元组返回,代码可读性更好,无需依赖out参数:interface IWorkerServiceFactory { [MustDisposeResource] (IDisposable Scope, IWorkerService Service) Create(); } class WorkerServiceFactory(IResolverContext ctx) : IWorkerServiceFactory { public (IDisposable Scope, IWorkerService Service) Create() { var scope = ctx.OpenScope(); var service = scope.Resolve<IWorkerService>(); return (scope, service); } } // 调用方代码 public void PrintData() { var (scope, worker) = workerFactory.Create(); using (scope) { Console.WriteLine(worker.GetData()); } } - 添加作用域名称(可选):给工厂创建的作用域添加名称,方便调试和跟踪生命周期:
var scope = ctx.OpenScope("WorkerServiceScope");
简化替代方案
如果使用DryIoc,可利用委托注入省去手动编写工厂类的代码,同时保持同样的生命周期管理能力:
// 注册创建作用域和服务的委托 container.RegisterDelegate<Func<(IDisposable, IWorkerService)>>(ctx => { return () => { var scope = ctx.OpenScope(); return (scope, scope.Resolve<IWorkerService>()); }; }, Reuse.Singleton); // 单例服务直接依赖该委托 class SingletonService(Func<(IDisposable, IWorkerService)> workerFactory) : ISingletonService { public void PrintData() { var (scope, worker) = workerFactory(); using (scope) { Console.WriteLine(worker.GetData()); } } }
内容的提问来源于stack exchange,提问作者patvax
相关产品推荐
相关产品推荐

