user1828922
user1828922

Reputation: 1

How to Dispose DI Injection chain from main instance

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

this is my pool class. i want that when i dispose the class. all dependencies should be stop working and dispose it self.

i tried and implement idisposable to all dependency to dispose but it doesnt work.

i also implement a thread to run function in thread and destroy it with thread abort. that also doesnt work.

is there any other way to do this?

Upvotes: 0

Views: 201

Answers (1)

Steven
Steven

Reputation: 172646

A component should not dispose any injected dependencies. The main reasons for this are:

  1. that component didn't create them, and therefore has no idea whether those dependencies should be disposed or not.
  2. consumers shouldn't even be aware that dependencies are disposable.

It is very common for a component to depend on a service with a longer lifestyle. In case the consuming component disposes that dependency, the application will break, because the dependency cannot longer be used, while it is configured to be used. Here's a simple example:

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

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

    // ...
}

This example contains a singleton UserRepository and a transient UserController. For each request, an new UserController is created (just picture an ASP.NET MVC application, and this will start to make sense). If the UserController would dispose the UserRepository, the next request would get a UserController that would depend on an already disposed UserRepository. This would obviously bad.

But besides this, IRepository<T> should not implement IDisposable. Implementing IDisposable means that the abstraction is leaking implementation details and therefor violates the Dependency Inversion Principle, that states:

Abstractions should not depend on details. Details should depend on abstractions.

Implementing IDisposable on an abstraction only makes sense if you are absolutely 100% sure that all implementations of that abstraction that you'll ever make need to dispose itself. But this hardly ever is the case. Just imagine having a FakeRepository<T> implementation in your unit tests. Such fake implementation never needs disposal and therefore not all implementations need disposal and you're leaking implementation details.

This simply means that you should move the IDisposable interface to the implementation. For instance:

public interface IRepository<T> { }

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

Note that having the IDisposable interface on an abstraction, while not all consumers are expected to call Dispose also means you are violating the Interface Segregation Principle that states that:

no client should be forced to depend on methods it does not use.

Advantage of this is that it becomes impossible for consuming components (such as the UserController) to accidentally call Dispose() and with that possibly break the system.

Another advantage is that since components don't need to dispose their dependencies, for most components there will be no disposal logic left, making the system considerably simpler and more maintainable.

Upvotes: 1

Related Questions