Neat Disposal Pattern

You know when you’ve been a c# developer too long when seeing a slightly neater and elegant disposal pattern gets you excited.

If you’ve been doing things properly, then you’ll already have components that are IDisposable because they need to release references (to aid garbage collection), unhook event handlers, dispose RX subscriptions  and clean up after themselves.

    public class MyComponent : IDisposable
    {
        // ...

        public void Dispose()
        {
            // Clean up component
        }
    }

Old School

Quite often, you’ll have sub-components that are also IDisposable and you need to make sure you dispose of those when you are disposed (presuming you’re responsible for their lifetime).

You could just fill your Dispose () method with individual calls to each of the IDisposables you hold. Straightforward if a little verbose.

    public class MyComponent : IDisposable
    {
        private ISubComponentA _a;
        private ISubComponentB _b;
        private ISubComponentC _c;

        public MyComponent(
            ISubComponentA a, 
            ISubComponentB b, 
            ISubComponentC c)
        {
            _a = a;
            _b = b;
            _c = c;
        }

        public void Dispose()
        {
            // Clean up component
            _a.Dispose();
            _b.Dispose();
            _c.Dispose();
        }
    }

Middle School

Or you might hold a List and add to it everything that needs disposing. Then in Dispose () you can loop over the list and dispose of everything. A bit neater.

    public class MyComponent : IDisposable
    {
        private List<IDisposable> _disposables = new List<IDisposable>(); 
        
        private ISubComponentA _a;
        private ISubComponentB _b;
        private ISubComponentC _c;

        public MyComponent(
            ISubComponentA a,
            ISubComponentB b,
            ISubComponentC c)
        {
            _a = a;
            _b = b;
            _c = c;

            _disposables.Add(_a);
            _disposables.Add(_b);
            _disposables.Add(_c);
        }

        public void Dispose()
        {
            // Clean up component
            _disposables.ForEach(d => d.Dispose());
            _disposables.Clear();
        }
    }

College

If you’re familiar with RX then you might have come across the CompositeDisposable to which you add IDisposables and then at some point simply dispose the CompositeDisposable. It takes care of disposing its contents.

using System.Reactive.Disposables;

    public class MyComponent : IDisposable
    {
        CompositeDisposable _compositeDisposable = new CompositeDisposable();

        private ISubComponentA _a;
        private ISubComponentB _b;
        private ISubComponentC _c;

        public MyComponent(
            ISubComponentA a,
            ISubComponentB b,
            ISubComponentC c)
        {
            _a = a;
            _b = b;
            _c = c;

            _compositeDisposable.Add(_a);
            _compositeDisposable.Add(_b);
            _compositeDisposable.Add(_c);
        }

        public void Dispose()
        {
            // Clean up component
            _compositeDisposable.Dispose();
        }
    }

University?

So the final neatening up that I saw recently was this.

You have a base class called DisposableObject. It has a method called AddDisposable(IDisposable x) which adds the x to a private CompositeDisposable.

DisposableObject then disposes of its CompositeDisposable in its Dispose method.

    public interface IDisposableObject: IDisposable
    {
        void AddDisposable(IDisposable disposableObject);
    }

    public class DisposableObject : IDisposableObject
    {
        CompositeDisposable _compositeDisposable = new CompositeDisposable();

        public void AddDisposable(IDisposable disposableObject)
        {
            _compositeDisposable.Add(disposableObject);
        }

        public virtual void Dispose()
        {
            _compositeDisposable.Dispose();
        }
    }

You then derive from DisposableObject and the idea is to pass any objects that we need disposing to the base class.

But here’s the neat bit.

Rather than calling the base class’ AddDisposable method directly, write an extension method that looks like this:

    public static class DisposableExtensions
    {
        public static T DisposeWith<T>(this T source, IDisposableObject target) where T : IDisposable
        {
            target.AddDisposable(source);
            return source;
        }
    }

This means that now the code can look like this:

    public class MyComponent : DisposableObject
    {
        private ISubComponentA _a;
        private ISubComponentB _b;
        private ISubComponentC _c;

        public MyComponent(
            ISubComponentA a,
            ISubComponentB b,
            ISubComponentC c)
        {
            _a = a;
            _b = b;
            _c = c;

            _a.DisposeWith(this);
            _b.DisposeWith(this);
            _c.DisposeWith(this);
        }
    }

Very readable and very neat and tidy.

It means that when you make an RX subscription, instead of storing that subscription in a member variable and remembering to dispose of it later, you can do this:

            IObservable<Trade> trades = _tradeService.GetTrades();

            var subscription = trades
                .Where(t => t.TradedAmount > 1000000000.00)
                .Subscribe(HandleLargeTrade)
                .DisposeWith(this);

And I thought that that was rather nice.

My latest thoughts are whether there is a neat way to null the references too. Hmm…

Advertisements

4 thoughts on “Neat Disposal Pattern

  1. Haha, it’s funny which bits of your code developers like. I’ve never thought about the journey I took to get there but when you put it like that it almost seems like I had a plan.

  2. Pingback: Neat Disposal Pattern (cont) « Paint the River

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s