For this very reason I've made my own IoC container which returns (in C#/.NET) disposable service wrappers, that when disposed of, will "do the right thing" in regards to the service.
Be it:
- Do nothing, when:
- The object does not implement IDisposable
- Is not container-scoped (in which case the container will keep track of it and return the same object more than once, and when the container is disposed of, the object will be too)
- It is not pooled
- It is not singleton-scoped (same as container-scoped, but a hierarchy of containers will store the singleton-scoped service in the topmost container)
- Dispose of the service (it has factory scope, and implements IDisposable)
- Return it to the pool
This means that all code that uses my services is inside a using-block, but the intent is more clear, at least to me:
using (var service = container.Resolve<ISomeService>())
{
service.Instance.SomeMethod();
}
basically it says: resolve a service, call SomeMethod on the service instance, and then dispose of the service.
Since knowledge of whether to dispose of the service instance or not isn't available to the consumer, there was either the choice of just ignoring IDisposable implementations altogether, or to dispose of all services which implement IDisposable. Neither was a good solution to me. The third choice was to wrap the service instance in an object that knew what to do with the service once the wrapper was disposed of.