.net – 依赖注入和IDisposable

我对使用Autofac的Idisposable实现中的dispose()方法有点困惑

说我的对象有一定的深度:

>控制器取决于IManager;
>经理依靠IRepository;
>存储库依赖于ISession;
> ISession是Idisposable.

这导致以下对象图:

new Controller(
    new Manager(
        new Repository(
            new Session())));

我是否还需要使我的Manager和Repository实现Idisposable,并在Controller中调用Manager.dispose(),在Manager中调用Repository.dispose()等,或者Autofac会自动知道我的调用堆栈中哪些对象需要正确处理? Controller对象已经是Idisposable,因为它派生自基本ASP.NET Web API控制器

资源的一般规则是:

He who owns the resource is responsible of disposing it.

这意味着如果一个类拥有一个资源,它应该以与它创建它相同的方法处置它,或者如果这不可能,这通常意味着拥有类必须实现Idisposable,因此它可以将资源部署在其中处理方法.

但重要的是要注意,一般来说,如果一个类负责创建它,那么它只拥有一个资源.但是当注入资源时,这意味着该资源在消费者之前就已存在.消费者没有创建资源,在这种情况下应该不处理它.虽然我们可以将资源的所有权传递给使用者(并在类的文档中传递所有权的传递),但通常不应传递所有权,因为这会使代码复杂化并使应用程序非常脆弱.

虽然在某些情况下转移对象所有权的策略可能有意义,例如对于可重用API的一部分类型(如System.IO.StreamReader),在处理作为对象图的一部分的组件时总是不好的(我们所谓的injectables).我将在下面解释原因.

因此,即使您的Controller依赖于需要处理的依赖项,您的控制器也不应该丢弃它们.原因很简单:

>由于消费者没有创建这种依赖关系,因此不知道该依赖关系的预期生命周期是什么.很可能依赖性应该比消费者的生命周期长.在这种情况下让消费者处理该依赖将导致应用程序中的错误,因为下一个控制器将获得已经处置的依赖关系,这将导致抛出ObjectdisposedException.
>即使依赖的生活方式等于消费者的生活方式,处置仍然是一个坏主意,因为这可以防止您轻松地将该组件替换为将来可能具有更长寿命的组件.一旦为更长寿命的组件替换该组件,您将必须遍历处理该依赖关系的所有组件,从而导致您在整个应用程序中进行彻底的更改.换句话说,您将通过这样做违反Open/closed principle,因为应该可以添加或替换功能而无需进行彻底的更改.
>如果您的使用者能够处置此依赖关系,这意味着您在该抽象上实现Idisposable.这意味着这种抽象漏掉了实现细节;这违反了Dependency Inversion Principle.在抽象上实现Idisposable时,您正在泄漏实现细节,因为该抽象的每个实现都不太可能需要确定性处理,因此您需要考虑某个实现来定义抽象.消费者不应该对实施有任何了解,无论是否需要确定性处置.
>让抽象实现Idisposable也会导致违反Interface Segregation Principle,因为抽象现在包含一个额外的方法(即dispose),并非所有消费者都需要调用.他们可能不需要打电话,因为 – 我们已经意识到 – 资源可能比消费者更长久.在这种情况下让它实现Idisposable是危险的,因为任何人都可以调用它上面的dispose导致应用程序中断.如果我们对测试非常严格,这也意味着我们必须测试消费者没有调用dispose方法.想想这将导致额外的测试代码.这是需要编写和维护的代码.

所以相反,我们应该只让实现实现Idisposable.这使得抽象的任何消费者都不会怀疑它是否应该调用dispose(因为没有dispose方法调用抽象).

现在因为只有实现实现了Idisposable,并且只有你的Composition Root创建了这个实现,所以它是组合根负责它的处理.如果你的DI容器创建了这个资源,它也应该处理它. Autofac实际上会为您做到这一点.你可以轻松测试这个.如果您在不使用DI容器(a.k.a.Pure DI)的情况下连接对象图形,则意味着您必须自己在组合根中处理这些对象.

要意识到这会使您的代码更简单.在抽象上实现Idisposable并让消费者处理它们的依赖关系将导致Idisposable像病毒一样通过你的系统传播(就像asynchronous programming spreads out like a virus一样污染你的代码库).

它展开,因为您总是可以想到需要清理其资源的抽象实现,因此您必须在每个抽象上实现Idisposable.这意味着每个需要一个或多个依赖项的实现也必须实现Idisposable,这会爬上对象图.这为系统中的每个类增加了大量代码和不必要的复杂性.

相关文章

迭代器模式(Iterator)迭代器模式(Iterator)[Cursor]意图...
高性能IO模型浅析服务器端编程经常需要构造高性能的IO模型,...
策略模式(Strategy)策略模式(Strategy)[Policy]意图:定...
访问者模式(Visitor)访问者模式(Visitor)意图:表示一个...
命令模式(Command)命令模式(Command)[Action/Transactio...
生成器模式(Builder)生成器模式(Builder)意图:将一个对...