views:

980

answers:

7

I'm finally wrapping my head around IoC and DI in C#, and am struggling with some of the edges. I'm using the Unity container, but I think this question applies more broadly.

Using an IoC container to dispense instances that implement IDisposable freaks me out! How are you supposed to know if you should Dispose()? The instance might have been created just for you (and therefor you should Dispose() it), or it could be an instance whose lifetime is managed elsewhere (and therefor you'd better not). Nothing in the code tells you, and in fact this could change based on configuration!!! This seems deadly to me.

Can any IoC experts out there describe good ways to handle this ambiguity?

+2  A: 

I think in general the best approach is to simply not Dispose of something which has been injected; you have to assume that the injector is doing the allocation and deallocation.

McWafflestix
This is very inconvenient, as I frequently want to inject disposable objects. In general, the semantics of IDisposable require the creator/owner of the object to Dispose of it at the right time. If the container is responsible, then the user of the instance needs to tell the container when it's done. This is easy to forget.
Mr. Putty
+2  A: 

This depends on the DI framework. Some frameworks allow you to specify whether you want a shared instance (always using the same reference) for every dependency injected. In this case, you most likely do not want to dispose.

If you can specify that you want a unique instance injected, then you will want to dispose (since it was being constructed for you specifically). I'm not as familiar with Unity, though - you'd have to check the docs as to how to make this work there. It's part of the attribute with MEF and some others I've tried, though.

Reed Copsey
+5  A: 

AutoFac handles this by allowing the creation of a nested container. When the container is finished with, it automatically disposes of all IDisposable objects within it. More here.

Samuel Jack
Very interesting. I didn't know anything abaout AutoFac. I don't think it would be too hard to do something like this with Unity. I'm going to have to think about this one a bit. Thanks!
Mr. Putty
It might be hard to do that with Unity, since deterministic disposal has been embedded into the architecture of Autofac since the beginning.
Rinat Abdullin
Castle Windsor is the other container that lets you do that, either using sub-container, scoped lifestyle or via explicitly releasing your components using `container.Release` method
Krzysztof Koźmic
+4  A: 

You definitely do not want to call Dispose() on an object that was injected into your class. You can't make the assumption that you are the only consumer. Your best bet is to wrap your unmanaged object in some managed interface:

public class ManagedFileReader : IManagedFileReader
{
    public string Read(string path)
    {
        using (StreamReader reader = File.OpenRead(path))
        {
            return reader.ReadToEnd();
        }
    }
}

That is just an example, I would use File.ReadAllText(path) if I were trying to read a text file into a string.

Another approach is to inject a factory and manage the object yourself:

public void DoSomething()
{
    using (var resourceThatShouldBeDisposed = injectedFactory.CreateResource())
    {
        // do something
    }
}
Michael Valenty
But I do want to inject IDisposable objects, and further, I may or may not need to Dispose() of them at the site of injection, depending on configuration.Your first example works when the underlying resource is accessed transiently, but doesn't help if the resource is more persistent. In the second example, it seems odd to me to inject a factory in this way; that is one of the major functions of the IoC model in the first place. If I apply IoC to this concept, I seem to end up back at the original question. I think the container itself needs to participate in this, a la AutoFac.
Mr. Putty
@Mr. Putty - dependency injection doesn't eliminate the need for factories, it just makes one (ab)use of them unnecessary. For example, when you don't know the type of the concrete dependency until runtime, or for expensive conditional dependencies (objects that you might not even need which take a lot of resources to create), you might want to inject a factory instead of the object itself. Depending on your DI framework's support for IDisposable, factory injection may be the best way - it's certainly more transparent than many of the alternatives. (+1)
Jeff Sternal
A: 

In the Unity framework, there are two ways to register the injected classes: as singletons (you get always the same instance of the class when you resolve it), or such as you get a new instance of the class on each resolution.

In the later case, you have the responsibility of disposing the resolved instance once you don't need it (which is a quite reasonable approach). On the other hand, when you dispose the container (the class that handles object resolutions), all the singleton objects are automatically disposed as well.

Therefore, there are apparently no issues with injected disposable objects with the Unity framework. I don't know about other frameworks, but I suppose that as long as a dependency injection framework is solid enough, it for sure handles this issue in one way or another.

Konamiman
+3  A: 

There's basically two ways I've seen this is handled:

  1. When you resolve a service to an object that implements IDisposable, the container will remember this. When you dispose of the container, that service will be disposed of as well.
  2. When you resolve a service, what you get back is not just the service object itself, but you also get a wrapper object, that implements IDisposable, and requires you to dispose of it. When you do, it will also know what to do with the actual service object you requested.

Of the 2, the third is the most common:

  • When you resolve to a service that implement IDisposable, don't give a damn and just leave the service object floating until garbage collection handles it.

This is basically just the IoC framework not providing you with any means at all to handle this problem. If you do, that's your case, not the framework's responsibility.

But, hang on, the problem gets more hairy when you consider it.

What if the service object you get back is a singleton? Even though it might implement IDisposable, should you dispose of it? How do you know? How can you find it? Can you find out? At the point when you say "I know this service will be a singleton", you've basically taking a sort of dependency and implemented special code to handle it. The point of IoC is to be able to substitute services without changing the code that consumes them. IDisposable throws a big spanner in the works of this process.

In short, the best solution with most of todays IoC frameworks is to implement services that doesn't implement/require IDisposable.

Lasse V. Karlsen
+1  A: 

Putting a facade in front of the container can resolve this as well. Plus you can extend it to keep track of a more rich life cycle like service shutdowns and startups or ServiceHost state transitions.

My container tends to live in an IExtension that implements the IServiceLocator interface. It is a facade for unity, and allows for easy access in WCf services. Plus I have access to the service events from the ServiceHostBase.

The code you end up with will attempt to see if any singleton registered or any type created implements any of the interfaces that the facade keeps track of.

Still does not allow for the disposing in a timely manner as you are tied to these events but it helps a bit.

If you want to dispose in a timely manner (aka, now v.s. upon service shutdown). You need to know that the item you get is disposable, it is part of the business logic to dispose of it, so IDisposable should be part of the interface of the object. And there probably should be verification of expectations untitests related to the dispose method getting called.

Bas Hamer