【问题标题】:IOC containers and IDisposableIOC 容器和 IDisposable
【发布时间】:2011-02-07 17:54:10
【问题描述】:

有人建议我,当使用 IOC 容器时,我应该改变这个:

class Foobar: IFoobar, IDisposable {};

进入这个:

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

我想知道这是否可行,或者它是否解决了一个问题并产生了另一个问题。它确实解决了我非常想这样做的问题:

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

现在我知道任何替代都不会导致运行时错误。

另一方面,现在我所有的模拟对象也必须处理 IDisposable。我对大多数任何模拟框架都可以轻松处理这个问题吗?如果是,那么也许这不是问题。

是吗?我应该注意另一个隐藏的问题吗?我肯定会想到,如果我使用 IOC 容器不是为了单元测试/模拟,而是为了真正的服务独立性,那么这可能是一个问题,因为也许我的可交换服务中只有一个实际处理非托管资源(现在我' m 必须在这些其他服务中实现空的“IDispose”操作)。

即使是后一个问题,我想我也可以忍受,以便获得使用上面演示的“使用”语句的能力。但我是在遵循一个流行的惯例,还是我错过了一个完全不同的更好的解决方案?

【问题讨论】:

标签: ioc-container idisposable


【解决方案1】:

在我看来,从 IDisposable 派生接口是一种设计味道,表明 抽象泄漏。作为 Nicholas Blumhardt put it:

接口 [...] 通常不应该是一次性的。定义接口的人无法预见它的所有可能实现——您总是可以想出几乎任何接口的一次性实现。

考虑为什么要将 IDisposable 添加到您的界面。这可能是因为您考虑了特定的实现。因此,实现会泄漏到抽象中。

一个称职的 DI 容器应该知道它何时创建了一次性类型的实例。当您随后要求容器释放对象图时,它应该自动处置一次性组件(如果根据他们的生活方式,他们的时间到了)。

我知道至少 Castle Windsor 和 Autofac 是这样做的。

所以在你的情况下,你应该像这样保持你的类型:

class Foobar: IFoobar, IDisposable {};

您可能会发现 Nicholas Blumhardt 的帖子 The Relationship Zoo 也很有趣 - 特别是关于 Owned&lt;T&gt; 的讨论。

【讨论】:

  • 有限资源访问(数据库、硬件等)的会话接口呢?这些可以 IDisposable 吗?
  • IDisposable 或 Owned&lt;T&gt;,但它基本上归结为同一件事。它仍然是一种气味,但有时可能是必要的。人们可以将工作单元模式视为一种替代方案,但即使这样也存在同样的潜在问题。注意气味很重要,但有时无法避免:/
  • 好的,所以也许“interface IFoobar : IDisposable”是 IOC 容器的适应,对于 IOC 容器“有时无法避免”。但是频率呢?假设我将一个 IOC 容器合并到现有代码(300 个类)中,它迫使我使用“气味”6 次。也许那时我耸了耸肩。但是,如果它影响了我 300 节课中的 85 节课,我不应该猛踩刹车并完全重新评估我在做什么(包括我是否应该放弃或切换 IOC 容器)?或者 IOC 容器的好处通常会超过这种特殊的气味吗?
  • 很少有 DI 容器本身带来好处,而是它所暗示的设计。在任何情况下,我都会使用经验法则,如果更改使代码库处于比以前更好的状态,那么它是值得的。
  • 不是 DI 的问题,是 .net 框架的问题,IDisposable 不时需要实现。 DI 容器仅在它是所有者时才负责处理。等待对象图被释放可能已经很晚了。对我来说最好的方法是:不要让 DI 以短暂的方式返回一次性对象。使用由 DI 控制的提升时间,避免对象需要 IDisposable 或提供工厂以指示客户端是所有者并且应尽可能短地持有对象。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-21
  • 1970-01-01
  • 2014-04-29
  • 2011-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多