使用 DI/IoC 容器时如何处理对象的处置?

问题描述 投票:0回答:1

我正在使用 DryIoc,但我认为这是一个适用于任何 IoC 容器的普遍问题。

考虑一个单例服务(我们称之为

SingletonService
)。每次调用
SingletonService
的一个函数时,都需要一组新的对象。为了简单起见,我们假设只有一个对象,称为
WorkerService
WorkerService
将使用非托管资源,因此需要进行处置。

我不清楚如何确保

WorkerService
在不再需要时立即被处理掉。据我所知,由于服务定位器反模式,在
SingletonService
中引用容器是不行的。

我想到的一个解决方案是将

WorkerServiceFactory
注入
SingletonService
WorkerServiceFactory
通过注入获取容器。然后工厂使用容器获取
WorkerService
并将其返回给SingletonService。
SingletonService
是负责处置
WorkerService
的人吗?是否有一个准则规定在容器中创建的对象应该由容器处理?或者我可以使用范围,但我不清楚如何使用。如果我要在
SingletonService
中创建一个新范围,它仍然会包含对容器的引用(至少在 DryIoc 中,除非我遗漏了一些东西)。在工厂中创建作用域是没有意义的,因为该作用域只能由工厂访问。

遇到这样的情况你会如何处理?

编辑1:

我想了一些,然后想出了这个:

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
只关心处理从工厂返回的范围,容器处理其他所有事情。这是一个合理的方法吗?

c# .net dependency-injection dispose dryioc
1个回答
0
投票

这看起来像是 Mark Seemann 所说的“强制依赖”问题的一个例子。那篇文章很好地探讨了这个问题,但是,尽管是通过略读,我看不到任何关于如何解决它的建议。 我过去广泛使用过

Castle.Windsor

。它有一个称为“类型化工厂设施”的功能。我并不是建议您开始使用 Castle.Windsor 来实现此功能,但我认为这是一种模式,可以为您的问题提供可能的答案。说实话,无论如何,你实际上已经找到了自己。 它使用基于接口的约定提供容器感知工厂实现。所以它本质上与你的IWorkerServiceFactory相同。关键部分是“释放”您通过工厂解析的组件部分。我对当前解决方案的看法是,将容器范围返回给调用者会让调用者对底层基础设施了解太多。类型化工厂方法通过接口上的“释放/销毁”方法抽象了生命周期管理。这样,调用者负责组件的清理,但机制是不透明的。我建议对你的工厂做类似的事情并封装/隐藏底层容器机制。

看起来类型化工厂功能也支持

IDisposable
,但这似乎是在工厂级别运行的。我不确定我将如何实现我自己的等效项,但这并不意味着您应该忽略它。 所以,类似:

interface IWorkerServiceFactory { IWorkerService Create(); void Release(IWorkerService workerService); } class WorkerServiceFactory(IResolverContext ctx) : IWorkerServiceFactory { public IWorkerService Create() { // I don't know DryIoc, so I'm guessing... return ctx.Resolve<IWorkerService>(); } public void Release(IWorkerService workerService) { return ctx.Release(workerService); } }

    

© www.soinside.com 2019 - 2024. All rights reserved.