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

本文关键字:DI 注入 处理 实例 | 更新日期: 2023-09-27 18:00:55

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

这是我的台球课。我想在处理类时这样做。所有依赖项都应该停止工作并自行处理。

我试着实现了对所有依赖项都可执行的idispoble-to-all dependency以进行处理,但它不起作用。

我还实现了一个线程来在线程中运行函数,并通过线程中止来销毁它。这也不起作用。

有别的办法吗?

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

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

  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,则下一请求将获得依赖于已处置的UserRepositoryUserController。这显然很糟糕。

但除此之外,IRepository<T>应该而不是实现IDisposable。实现IDisposable意味着抽象正在泄露实现细节,因此违反了依赖反转原则,即:

摘要不应依赖于细节。详细信息应取决于抽象。

在抽象上实现IDisposable只有在您绝对100%确信所有该抽象的实现都需要自行处理的情况下才有意义。但事实并非如此。想象一下,在单元测试中有一个FakeRepository<T>实现。这样的伪实现永远不需要处理,因此并不是所有的实现都需要处理,并且您正在泄露实现细节。

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

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

请注意,在抽象上拥有IDisposable接口,虽然并非所有消费者都应该调用Dispose,但这也意味着您违反了接口分离原则,该原则规定:

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

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

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