IOC Containers and IDisposable

Oct 22, 2009 at 7:29 PM

I have not yet used IOC containers, but I'm studying TDD and am evaluating IOC container implementations (Castle Windsor, Autofac, Unity, StructureMap, etc).

In general, I'm finding there is a noticeable problem regarding the handling of IDisposable objects from an IOC container.  The topic has been discussed here:

...but was not actually answered.

The problem is that there is no way for a client class to know if an injected dependency is IDisposable (without using reflection, which is NOT acceptable).  Instead, the IOC containers themselves implement IDisposable and use reflection internally to determine which created / provided objects are IDisposable.  Thats good.  However, the Unity container doesn't keep track of most objects it creates - which makes calling Dispose() on the Unity container near useless.  Other containers, such as Windsor and Autofac, keep track of *all* IDisposable objects they make / contain.  But even so, there is still a problem.  Calling Dispose() on those containers effectively ends the lifecycle of the container, which leaves the client orphaned from further IOC access.  To compensate, the application code will often post-pone calling Dispose() on the container as long as possible - the opposite of what normally would be designed and coded.

If there is something I'm completely misunderstanding, please explain.  Otherwise, I'm hoping someone can discuss strategies that minimize this problem. 

Until that time, I'm considering either:
1) Don't use TDD / IOC containers.  Instead use traditional testing techniques (emphasis on component levelization and interface based testing).
2) If using TDD / IOC containers, then:
  a) don't use Unity
  b) Never Resolve() on the parent container directly.  Instead, every recipient of the parent immediately makes a child container(s) and calls resolve on that instead.  When finished, the client always calls Dispose() on the child container.  So if there were any IDisposables created, they are freed quickly.

My above solution #2 ASSUMES that the child container tracks objects provided by Resolve(), even though the Register() may have been made on the parent container.

In Summary: "tight" code and design presumes calling Dispose() the moment a wrapped, non-managed resource is no longer needed.  But the design and code needs to *know* the wrapper contains a non-managed resource in order to behave that way.  With an IOC container, the client code no longer knows if the injected object is wrapping a non-managed resource.   The story starts to devolve from that point forward.