views:

158

answers:

9

Say you have 3 classes that implement IDisposable - A, B and C. Classes A and B are both dependent on class C.

  1. Would it be correct to say that classes A and B's typical implementation of Dispose() would be:

    public void Dispose()
    {
        if (m_C != null) m_C.Dispose();
    }
    
  2. If there's an instance of A and and instance of B that share the same instance of C, how would you overcome the problem that disposing an instance of A would damage the instance of B?

  3. Last minute addendum - If in point 2 it's a DI container that instantiates all instances, who is responsible for disposing of the objects? Is it the container itself? How?

Thanks, urig

+4  A: 

Doing a null check won't help as if B disposes of C this won't update A's reference.

You have to ensure that only one of the classes has ownership of C. This owner class is then responsible for its disposal.

Generally the class that creates C should be the class that disposes of it.

Mongus Pong
A: 

Two methods I could think would be to:

  1. Create a parent collection within C, and in the dispose method of A and B, remove self from the child's parent collection. Then if the parent collection count is 0, call dispose.
  2. Lazy load a property within both A and B to access C. Perform a null check on C, if some other object has destroyed it, reinstantiate it (if possible).
Joel Etherton
+10  A: 

The dispose pattern relies on there being a well-established "owner" who gets to decide when the resource should be disposed of.

If A and B need to refer to the same instance of C, then only one of them should act as "owner".

While you can do what amounts to reference counting, I usually find it's better to just document who "owns" what. For example, when you create a Bitmap with a stream, from that point on the Bitmap owns the stream, and you shouldn't dispose it yourself. This can cause a few issues, but it's ultimately simpler than trying to dredge up reference counting.

Jon Skeet
Oh wow. I got an answer for Jon Skeet! But considering my scenario is typical of DI and A and B rely on C indepedently from each other, who is the owner?
urig
There's a reason Jon has 195k rep :)
Brian Rasmussen
To clarify, in my scenario not A nor B are the distinct owners of C. For example imagine C pushes data in real time and both A and B consume it. A DI container is in charge of instantiating C for A and for B, but who is in charge of disposing of it?
urig
@urig: In that situation, when would you *want* it to be disposed? I usually find that there are ways of designing around this which avoid the problem entirely, but it does depend on the situation.
Jon Skeet
Thanks again for helping Jon. In my scenario I'm disposing when my host process shuts down. But I could imagine a case when A is transient whereas B is a singleton. Maybe I shouldn't make A and B dispose of C and leave it solely up to the DI container?
urig
@urig: That sounds like it may well be the best place, yes. If it's meant to last for the duration of the app, then the DI is probably the most apprporiate "owner".
Jon Skeet
Thanks Jon and everyone. I understand now that the principle is that whoever created the object is responsible for disposing of it. In my case it's the DI container. Luckily I'm using Castle Windsor which has some flexibility in managing disposal through lifestyle configuration and explicit Release() methods.
urig
@urig: This is a common issue in C++, where *all* objects should have an owner. Be grateful there's a garbage collector!
BlueRaja - Danny Pflughoeft
A: 
  1. I usually do it this way, tends to be accepted and it definitely works. However if another object has disposed it, null checking won't stop dispose being called again because it won't be null. C's disposal should defend against multiple calls however.

  2. Very good question. Immediately what springs to mind is there needs to be logic to know how many counts are currently on that object, so it's own disposal routines can defend itself. Semaphores do this, but are heavy.

I'd also question where you'd see this in a real-world example, might be a design discrepancy. Update: as others have mentioned, it's coming down to a design issue - you get a similar effect when using CCWs, someone else releases the underlying COM object where other users might still use it.

Adam
A: 

That would be a correct implementation: however, you might want to save references to all objects depending on a specific instance of C in both A and B, and have a check for that list to be empty (except for the currently disposing object) in C's Dispose method.

Tomas Lycken
+1  A: 

Only one instance must be the owner, and it is responsible for disposing. Non-owner instance should get C reference using function like Attach, and it should not dispose it.

Alex Farber
+1  A: 

Who created the instance? This is generally the owner and should be responsible for Disposing of the instance.

Chances are you have an "outer" class that created C and then passed it, directly or indirectly, into A and B. This is probably the natural candidate who has responsibility for the lifecycle of C, and should be disposing of it.

[Edit: in reponse to OP's comment] It sounds like maybe you should have another look at the design here. Is this pointing to a refactor being needed?

You have a class C which needs disposing, that is used by both A and B; should you have a class who has overall responsibility for marshalling C through A and B, rather than having them create C from the DI container themselves? Or is C really more of a singleton. Does it even really need disposing?

I guess all I'm saying is that this feels like it may point to a design that needs a bit of a change; have another look with a critical eye.

Rob Levine
Thanks for helping. That's a good point. I failed to originally mention this but this is a DI scenario. The class that instantiates A, B and C is a DI container! Is the DI container responsible for disposing?
urig
Not sure if it's a design issue. The scenario is legit - C is a service provider, A is transient but B is a singleton. The problem was in my assumption that whoever uses C should dispose of it. That is incorrect. The correct pattern, like you pointed out, is that whoever created C should dispose of it.
urig
+1  A: 

Last minute addendum - If in point 2 it's a DI container that instantiates all instances, who is responsible for disposing of the objects? Is it the container itself? How?

Yes, the container owns any IDisposable objects it creates. The container disposes these objects when it is disposed itself. All DI containers should already do this by default.

Sometimes the DI framework gives you a way to take ownership. For example, in Autofac you can ask for an Owned<T> to be injected, and then you can safely call Owned<T>.Dispose() yourself when you're done with the object. This is especially useful if you're dynamically creating instances via an injected Func<Owned<T>> factory. Note that such "owned instances" are not intended to be shared.

Wim Coenen
A: 

In addition to what Jon said - the creator is the owner and should dispose the Disposable.

In this case it's the container, and the container is responsible for disposing the components. Not every component supports this (or at least not every one fully). Castle Windsor does. Also Autofac supports it.

Krzysztof Koźmic