【问题标题】:How to Dispose DI Injection chain from main instance如何从主实例处理 DI 注入链
【发布时间】:2015-07-04 20:39:16
【问题描述】:

https://github.com/int6/CoiniumServ/blob/develop/src/CoiniumServ/Pools/Pool.cs

这是我的泳池课。当我处理课程时,我想要那个。所有依赖项都应该停止工作并自行处理。

我尝试对所有依赖项实施可处置的处置,但它不起作用。

我还实现了一个线程以在线程中运行函数并通过线程中止将其销毁。这也行不通。

还有其他方法吗?

【问题讨论】:

标签: c# dependency-injection idisposable tinyioc


【解决方案1】:

组件应该处理任何注入的依赖项。主要原因是:

  1. 该组件没有创建它们,因此不知道是否应该释放这些依赖项。
  2. 消费者甚至不应该意识到依赖项是一次性的。

组件依赖于寿命更长的服务是很常见的。如果消费组件处理该依赖项,则应用程序将中断,因为该依赖项在配置为使用时无法再使用。这是一个简单的例子:

// Singleton
private static readonly IRepository<User> repository = new UserRepository();

public IController CreateController(Type controllerType) {
    if (controllerType == typeof(UserController)) {
        return new UserController(repository);
    }

    // ...
}

此示例包含一个单例UserRepository 和一个瞬态UserController。对于每个请求,都会创建一个新的UserController(只需想象一个 ASP.NET MVC 应用程序,这将开始有意义)。如果UserController 将释放UserRepository,则下一个请求将获得一个UserController,该UserController 将依赖于已释放的UserRepository。这显然很糟糕。

但除此之外,IRepository&lt;T&gt; 应该实现IDisposable。实现IDisposable 意味着抽象泄漏了实现细节,因此违反了Dependency Inversion Principle,它指出:

抽象不应依赖于细节。细节应该取决于 抽象。

仅当您绝对 100% 确定您将需要处理的该抽象的所有实现时,在抽象上实现 IDisposable 才有意义。但这几乎从来没有发生过。想象一下在你的单元测试中有一个FakeRepository&lt;T&gt; 实现。这种虚假的实现永远不需要处置,因此并非所有实现都需要处置,而且您正在泄漏实现细节。

这只是意味着您应该将IDisposable 接口移至实现。例如:

public interface IRepository<T> { }

public class UserRepository : IRepository<User>, IDisposable { }

请注意,在抽象上使用IDisposable 接口,虽然并非所有消费者都应该调用Dispose,但这也意味着您违反了Interface Segregation Principle 的规定:

不应强迫任何客户端依赖它不使用的方法。

这样做的好处是,消费组件(例如UserController)不可能意外调用Dispose(),这可能会破坏系统。

另一个优点是,由于组件不需要释放它们的依赖关系,因此对于大多数组件来说,不会留下任何释放逻辑,从而使系统变得更加简单和可维护。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    • 2011-01-25
    • 1970-01-01
    相关资源
    最近更新 更多