https://github.com/int6/CoiniumServ/blob/develop/src/CoiniumServ/Pools/Pool.cs
这是我的泳池课。当我处理课程时,我想要那个。所有依赖项都应该停止工作并自行处理。
我尝试对所有依赖项实施 idisposable 来处理,但它不起作用。
我还实现了一个线程以在线程中运行函数并通过线程中止将其销毁。那也行不通。
有没有其他方法可以做到这一点?
https://github.com/int6/CoiniumServ/blob/develop/src/CoiniumServ/Pools/Pool.cs
这是我的泳池课。当我处理课程时,我想要那个。所有依赖项都应该停止工作并自行处理。
我尝试对所有依赖项实施 idisposable 来处理,但它不起作用。
我还实现了一个线程以在线程中运行函数并通过线程中止将其销毁。那也行不通。
有没有其他方法可以做到这一点?
组件不应释放任何注入的依赖项。主要原因是:
组件依赖于寿命更长的服务是很常见的。如果消费组件处理该依赖项,则应用程序将中断,因为该依赖项在配置为使用时无法再使用。这是一个简单的例子:
// 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
抽象不应该依赖于细节。细节应该取决于抽象。
仅当您绝对 100% 确定您将要进行的该抽象的所有实现都需要自行处理时,在抽象上实现IDisposable
才有意义。但这几乎从来没有发生过。想象一下在你的单元测试中有一个实现。这种虚假的实现永远不需要处置,因此并非所有实现都需要处置,并且您正在泄漏实现细节。FakeRepository<T>
这仅仅意味着您应该将IDisposable
接口移至实现。例如:
public interface IRepository<T> { }
public class UserRepository : IRepository<User>, IDisposable { }
请注意,将IDisposable
接口放在抽象上,虽然并非所有消费者都应该调用Dispose
也意味着您违反了接口隔离原则,该原则指出:
不应强迫任何客户依赖它不使用的方法。
这样做的好处是,使用组件(例如UserController
)不可能意外调用Dispose()
并因此可能破坏系统。
另一个优点是,由于组件不需要释放它们的依赖关系,因此对于大多数组件来说,不会留下任何释放逻辑,从而使系统更加简单和易于维护。