IOC容器和IDisposable

9

有人建议我,在使用IOC容器时,应该将这个改成:

class Foobar: IFoobar, IDisposable {};

转化为这样:

interface IFoobar: IDisposable{};
class Foobar : IFoobar{};

我在想这样做是否可以,或者它解决了一个问题但又带来了另一个问题。当然,它解决了我非常想做这件事的问题:

using( IFoobar = myContainer.Resolve<IFoobar>() )
{ ... }

现在我知道任何替代品都不会引起运行时错误。

另一方面,现在我的所有模拟对象也必须处理IDisposable。我是否正确地认为,大多数模拟框架都可以轻松处理这个问题?如果是的话,那么这可能不是一个问题。

还是有问题吗?我应该注意到另一个隐藏的陷阱吗?当然,我想到了一个问题,如果我使用IOC容器而不是用于单元测试/模拟,而是用于真正的服务独立性,那么这可能是一个问题,因为只有我的一个可交换服务实际上涉及非受控资源(现在我必须在这些其他服务中实现空的“IDispose”操作)。

即使是后一种问题,为了获得像上面演示的“using”语句的能力,我想我也可以接受。但是,我是否遵循一种流行的惯例,或者我错过了一个完全不同且更好的解决方案?


3
谁推荐的?用于什么容器? - Mauricio Scheffer
你看过https://dev59.com/ZnNA5IYBdhLWcg3wX8rk吗? - Mauricio Scheffer
上面展示的技术是我与另一位工程师合作时建议的。 是的,我已经看过那个stackoverflow链接了。实际上,它启发我开始了这个线程: http://groups.google.com/group/structuremap-users/browse_thread/thread/6be80baf98c25820 简而言之,建议是要么(1)不要在Unity中使用IDisposable对象,要么(2)不要使用Unity。总的来说,这给了我三个建议。 - Brent Arias
1个回答

11

在我的看法中,从IDisposable继承一个接口是一种设计气味,表明存在泄漏的抽象。正如Nicholas Blumhardt 所说:

一个接口...通常不应该是可处理的。定义接口的人无法预见所有可能的实现方式 - 你几乎可以为任何接口想出一个可处理的实现方式。

考虑为什么要将IDisposable添加到您的接口中。这可能是因为你有特定的实现方式。因此,实现会泄漏到抽象中。

值得一提的是,一个好的DI容器应该知道它何时创建了一个可处理类型的实例。当你随后请求容器释放一个对象图时,如果根据其生命周期已经过期,它应该自动处置可处理组件。

我知道至少Castle Windsor和Autofac能够做到这点。

因此,在您的情况下,您应该保持您的类型不变:

class Foobar: IFoobar, IDisposable {};

你可能会发现Nicholas Blumhardt的文章《关系动物园》也很有趣,特别是对Owned<T>的讨论。


有关于受限资源访问(数据库、硬件等)的会话接口怎么样?它们可以是IDisposable吗? - xofz
IDisposable或Owned<T>,但基本上归结为同一问题。这仍然是一个坏味道,但有时确实必要。人们可以考虑使用工作单元模式作为替代方案,但它甚至也受到了同样的潜在问题的影响。重要的是要意识到这种情况,但有时候无法避免:/ - Mark Seemann
好的,那么"interface IFoobar : IDisposable"可能是IOC容器的一种适应方式,有时候不可避免。但是频率呢?假设我将一个IOC容器纳入现有的代码(包含300个类),其中强制我使用6次"smell",也许我会无所谓。但如果它影响了我的300个类中的85个,难道我不应该刹车并全面重新评估我的做法(包括是否应该放弃或切换IOC容器)吗?或者说,尽管存在这种"smell",IOC容器的好处通常仍然超过它的负面影响吗? - Brent Arias
3
容器本身很少带来好处,但它所暗示的设计却有益处。无论如何,我会遵循这样一条经验法则:如果一项更改让代码库变得比之前更好,那么就值得去做。 - Mark Seemann
这不是 DI 的问题,而是 .net 框架的问题,因为有时需要在实现中使用 IDisposable。如果 DI 容器是所有者,则只负责处理释放。等待对象图被释放可能已经太晚了。对我来说,最好的方法是:不要让 DI 以瞬态方式返回可处置对象。使用由 DI 控制的生命周期,避免对象需要 IDisposable 或提供工厂以指示客户端是所有者,并应尽可能短地持有对象。 - Remco te Wierik
@RemcoteWierik,确实如你所描述的那样,我在我的书籍中描述了这两个选项。 - Mark Seemann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接