如何从主实例处理DI注入链
本文关键字:DI 注入 处理 实例 | 更新日期: 2023-09-27 18:00:55
https://github.com/int6/CoiniumServ/blob/develop/src/CoiniumServ/Pools/Pool.cs
这是我的台球课。我想在处理类时这样做。所有依赖项都应该停止工作并自行处理。
我试着实现了对所有依赖项都可执行的idispoble-to-all dependency以进行处理,但它不起作用。
我还实现了一个线程来在线程中运行函数,并通过线程中止来销毁它。这也不起作用。
有别的办法吗?
组件不应处理任何注入的依赖项。主要原因是:
- 该组件没有创建它们,因此不知道是否应该处理这些依赖关系
- 消费者甚至不应该意识到依赖关系是一次性的
组件依赖于使用寿命更长的服务是非常常见的。如果使用组件处理该依赖关系,则应用程序将中断,因为在配置为使用该依赖关系时,该依赖关系将无法再使用。这里有一个简单的例子:
// 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
,则下一请求将获得依赖于已处置的UserRepository
的UserController
。这显然很糟糕。
但除此之外,IRepository<T>
应该而不是实现IDisposable
。实现IDisposable
意味着抽象正在泄露实现细节,因此违反了依赖反转原则,即:
摘要不应依赖于细节。详细信息应取决于抽象。
在抽象上实现IDisposable
只有在您绝对100%确信所有该抽象的实现都需要自行处理的情况下才有意义。但事实并非如此。想象一下,在单元测试中有一个FakeRepository<T>
实现。这样的伪实现永远不需要处理,因此并不是所有的实现都需要处理,并且您正在泄露实现细节。
这只是意味着您应该将IDisposable
接口移动到实现。例如:
public interface IRepository<T> { }
public class UserRepository : IRepository<User>, IDisposable { }
请注意,在抽象上拥有IDisposable
接口,虽然并非所有消费者都应该调用Dispose
,但这也意味着您违反了接口分离原则,该原则规定:
任何客户端都不应该被迫依赖于它不使用的方法。
这样做的好处是,消耗组件(如UserController
(不可能意外调用Dispose()
,从而可能破坏系统。
另一个优点是,由于组件不需要处理它们的依赖关系,因此对于大多数组件来说,将不剩下处理逻辑,从而使系统变得更加简单和可维护。