Wednesday 18 July 2012

Back to basics (IDisposable)

In simple terms Disposable pattern provides a method to de-allocate resource in a deterministic fashion.

The .NET Framework provides the  "IDisposable" interface which we should use to implement the disposable pattern. The interface is very simple (see below).

        public interface IDisposable
        {
            void Dispose();
        }


The "expensive" resources are considered to be calls to files, databases, streams. We should consider implementing IDisposable pattern and gracefully release resources where necessary. So, how do we go about implementing the IDisposable pattern. Consider the following code snippet.

    internal class ExpensiveResource : IDisposable
    {
        private bool _disposed = false;

        public void DoExpensiveWork()
        {
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool disposing)
        {
            if (_disposed)
            {
                return;
            }

            if (disposing)
            {
                ReleaseExpensiveResources();
                _disposed = true;
            }
        }

        private void ReleaseExpensiveResources()
        {

        }
    }

 To start, we have implemented the "IDisposable" interface for the type "ExpensiveResource". We have a overloaded  "Dispose" method. We use the overloaded method to add our custom code (i.e. code to release resources). 

Most importantly, the "Dispose" method can be called multiple times.Therefore we need to add safe guards in place. This is where "_disposed" field comes into play.

Since we are taking the ownership of disposing the object, there is no need for the Garbage Collector (GC) to call the "Finalize" method to dispose the object. Therefore we can suppress the call to Finalize. This is carried out by calling the "GC.SuppressFinalize(this))".

The C# "using" keyword can be used to elegantly dispose a disposable object. The consumer can write the following.

    internal class MyTestClass
    {
        public void DoStuff()
        {
            using (var expensiveWork = new ExpensiveResource())
            {
                // Do work
            }  - (1)
        }
    }

By the time the execution reach (1) the dispose defined in the type is called and object is disposed. 

.NET Tasks and IDisposable

.NET Framework "Task" by design implements the "IDisposable" interface, therefore an disposable object. But if we have to keep calling dispose at the end of each Task, then the source code will most surely become unreadable.

Read the following post from Stephen Toub - MSFT for more on disposing Tasks.

[The recommendation is not to dispose a Task unless you explicitly cause a Task to allocate a  IAsyncResult.AsyncWaitHandle.]

No comments:

Post a Comment