如何从主实例处理DI注入链

时间:2015-07-03 16:24:45

标签: c# dependency-injection idisposable tinyioc

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

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

我尝试并实现了所有依赖关系的idisposable,但它不起作用。

我还实现了一个线程来运行线程中的函数并使用线程中止来销毁它。那也行不通。

有没有其他方法可以做到这一点?

1 个答案:

答案 0 :(得分:1)

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

  1. 该组件没有创建它们,因此不知道是否应该处理这些依赖项。
  2. 消费者甚至不应该意识到依赖是一次性的。
  3. 组件依赖于具有较长生活方式的服务是很常见的。如果使用组件处理该依赖项,则应用程序将中断,因为在将其配置为使用时,不能再使用该依赖项。这是一个简单的例子:

    // 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,这将取决于已经处置UserRepository。这显然很糟糕。

    但除此之外,IRepository<T>应该实施IDisposable。实现IDisposable意味着抽象漏掉了实现细节,因此违反了Dependency Inversion Principle,其中指出:

      

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

    在抽象上实现IDisposable只有在绝对100%确定所有实现的抽象时才有意义,这些抽象是你需要自己处理的。但事实并非如此。试想在单元测试中实现FakeRepository<T>。这样的虚假实现永远不需要处理,因此并非所有实现都需要处理,而且您正在泄漏实现细节。

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

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

    请注意,在抽象上使用IDisposable接口,而不是所有消费者都应该调用Dispose也意味着您违反了Interface Segregation Principle声明:

      

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

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

    另一个优点是,由于组件不需要处理它们的依赖关系,因此对于大多数组件而言,将不会留下任何处理逻辑,从而使系统更加简单和易于维护。