tags:

views:

107

answers:

5

Imagine a:

public class Global : IDisposable 
{
    private static readonly List<IDisposable> Disposables = new List<IDisposable>();

    public void ApplicationStart()
    {
        var heavyLifter = new HeavyLifter();
        Disposables.Add(heavyLifter);
            // register a few more
    }

    public void Dispose()
    {
        Disposables.ForEach(d => d.Dispose());
    }
}

I am somewhat inexperienced with IDisposable. Is this a viable pattern?

A: 

Your code implies that HeavyLifter implements IDisposable. So all you need to do is call its Dispose method in the Application_End eventhandler.

Peter Bromberg
+3  A: 

From what I understand, you're creating a component that will use (I assume) multiple resources that implement IDisposable, and you're simply looking for a way to maintain a list of IDisposable objects within your component and just iterate over the list rather than calling Dispose on each item by name, is that correct?

If so, there's nothing wrong with that. However, your list should not be static, it should be per-instance.

Adam Robinson
When I saw this I immediately thought base class with protected members.
Joshua
+1  A: 

Well on one level IOC containers such as Unity can offer exactly this sort of functionality:

http://msdn.microsoft.com/en-us/library/ff663144.aspx

You delegate responsibility for creating objects to the IOC container, and can specify a LifetimeMangement option. This can include registering with the container for later disposal e.g. calling disposal on the container when an application shuts down, or when a form is closed.

For short lived objects you probably want to manage disposal yourself, but for longer lived objects an IOC type repository pattern with object disposal can work very well. Works well for me. :)

A good understanding of Disposal is always a good thing though.

chibacity
Yes of course a container will do something like that, but I am not actually registering components here, that I will access later. These are applications, that will live on their own thread, doing their own thing during the lifetime of the application. In fact each of them might have their own container :)
Jan Limpens
Unity is pretty sophisticated and seems to offer something that will do exactly what you are trying to do. You can create child containers and it knows about threads too...
chibacity
+1  A: 

You are working from the assumption that an outer class would have special knowledge of the lifetime of an object so that it call Dispose() at the right time. That rarely works, only the client code knows when it is done with an object.

With your class as written, you achieve the exact opposite goal, you'll keep the objects alive much longer than necessary. Not even the garbage collector could run the finalizer because you keep holding on to the object until some magic moment in time where all objects are ready to be disposed. The usual term for this is "memory leak". Don't do this.

Hans Passant
A: 

Ostensibly, this approach makes sense when you cannot make the disposal thread-safe (for example when talking to COM objects, which MUST be released on the same thread). However, in practice, you would find that this approach leads to objects living longer than they should.

I would strive to make the disposal thread safe, that way you can call Dispose from the finalizer and achieve truly automatic lifetime management. You have to be careful as might not be appropriate for some types of resources - like file or network handles, which might need tighter control. Otherwise, this is the best solution to this problem.

If the disposal HAS to be on the same thread then you are in a bit of a pickle. If the object needing disposing is in the model layer (as in business rules object) - it's quite likely it has layers of UI on top of, needing complex logic to dispose it (like events after a window is closed). It's a lose/lose situation and a choice between objects living forever (like your original solution) and complex disposal logic (which turns ugly pretty quickly).

Perhaps something to experiment with. You could separate the disposable resource into its own class and have the factory maintain a strong reference to it. The resource object maintains a weak reference back to business object. When the business object is finalized, WeakReference will return null, thus enabling you to make pass over the disposables and dump the ones that are no longer needed.

public class Global {
    private static readonly List<Resource> Disposables = new List<Resource>();

    public HeavyLifter GetHeavyLifter()
    {
        var resource = new HeavyLifterResource();
        var heavyLifter = new HeavyLifter(resource);
        resource.BusinessObject = heavyLifter;
        Disposables.Add(resource);
    }

    public void DisposeAll()
    {
        Disposables.ForEach(d => d.CleanUp());
    }
}

public abstract class Resource : IDisposable {

    WeakReference<object> m_BusinessObject;
    public WeakReference<object> BusinessObject {get;set;}

    public CleanUp() {
      if (!m_BusinessObject.IsAlive)
        Dispose();
    }
}

public HeavyLifter {
    public HeavyLifter (Disposable d) {
      m_resourceObj = d;
    }

    HeavyLifterResource m_resourceObj;
}

public class HeavyLifterResource :Resource {
    public void Dispose() {
      //disposal
    }
}

Let me again reiterate that the above approach is only appropriate for a certain class of objects. You wouldn't want to handle your network connections in such fuzzy way, but you can, for example, do this for business objects that need a network connection to dispose themselves. Even then, this is only appropriate when such connection is persistent through the lifetime of the application.

Igor Zevaka