Click here to Skip to main content
15,880,503 members
Articles / Programming Languages / Visual Basic
Article

Simplified Resource Management with the DisposableCollection Class

Rate me:
Please Sign up or sign in to vote.
4.42/5 (8 votes)
26 Sep 20044 min read 55.2K   367   17   4
This article demonstrates how a strongly typed collection of IDisposable objects can be used to simplify the management of multiple resources in .NET.

Introduction

Properly cleaning up objects that reference unmanaged resources such as database connections and GDI handles is an essential part of bullet-proof .NET Framework programming. In this article, we will see how to use a disposable strongly typed collection of IDisposable objects to simplify a common resource management scenario.

Background

Best .NET programming practices dictate that we should not wait for the garbage collector to dispose off managed objects that wrap unmanaged resources. These include GDI+ objects (which wrap Windows GDI resources, a notorious source of leaks in traditional Win32 programming) and database connections. Unless we explicitly dispose off such objects, it's theoretically possible that we will exhaust the system of the underlying resources before the finalizers of the managed objects have the chance to free them up. The IDisposable interface is provided and implemented by these objects to facilitate their deterministic cleanup.

Unfortunately, in Visual Basic .NET, this often forces us to write annoying and ugly code such as the following:

VB
Dim myPen As Pen
Try
    myPen = new Pen(Color.Red)
    'Do stuff with myPen
Finally
    If Not myPen Is Nothing Then
        myPen.Dispose()
    End If
End Try

In C#, the situation is made somewhat better by the presence of the using statement, which opens a scope at the end of which a given object will be disposed, regardless of whether the scope is exited normally or via an exception. Thus, the previous VB.NET code cleans up to the following in C#:

C#
using( Pen myPen = new Pen(Color.Red) )
{
    // Do stuff with myPen
}

Clearly, this removes a lot of our programming burden if we're using C#. Often, particularly in GDI+ code, you will find yourself working with multiple IDisposable objects at the same time. If these objects are of the same type, you may put them all inside the same using statement:

C#
using( Pen myRedPen = new Pen(Color.Red),
    myBluePen = new Pen(Color.Blue) )
{
    // Do stuff with both pens
}

When working with multiple IDisposable objects, chances are they won't always be of the same type. For instance, you'll need a Font and a Brush if you want to use the Graphics.DrawString method to paint some text. Unfortunately, here's where the using statement starts to break down, because the following code generates a compile error:

C#
using( Font myFont = new Font("Arial", 16),
    SolidBrush myBrush = new SolidBrush(Color.Blue) )
{
    // COMPILE ERROR!
}

That snippet doesn't compile because C# doesn't let you have more than one type in a single using statement. So, your next alternative is to nest using statements like this:

C#
using( Font myFont = new Font("Arial", 16) )
{
    using( SolidBrush myBrush = new SolidBrush(Color.Blue) )
    {
        {
            // Do stuff with a font and a brush
        }
    }
}

But use more than a couple of levels of nesting, and your code gets ugly pretty quickly. This caused me to set out in search of a better solution.

Using the code

To provide for easier IDisposable management in situations like these, my solution is the DisposableCollection class. This class combines a very typical CollectionBase implementation with a very typical IDisposable implementation. By combining those two abstractions, you get a simpler programming model which will hopefully encourage you to be more diligent about ensuring your IDisposables are immediately disposed. In C#, the snippet using both a Pen and a Brush turns into this:

C#
using( DisposableCollection dc = new DisposableCollection() )
{
    SolidBrush myBrush = null;
    Font myFont = null;

    dc.Add( myBrush = new SolidBrush(Color.Red) );
    dc.Add( myFont = new Font("Arial", 16) );

    // Do stuff with a font and a brush. They'll be disposed of by the
    // DisposableCollection's Dispose method at the end.
}

The DisposableCollection's mission in life is to serve as a working repository (specifically, a strongly-typed collection) for IDisposable objects that is itself disposable. Thus, you can insert it into a using statement and know that whatever you add to it will be disposed when the DisposableCollection's using block terminates.

You can write similar code inside the Try metaphor in VB:

VB
Dim dc As New DisposableCollection
Try
    myPen = new Pen(Color.Red)
    dc.Add(myPen)
    'Do stuff with myPen
Finally
    dc.Dispose()
End Try

Included are two solutions, one in C# and one in VB.NET, that implement some trivial form drawing, using the DisposableCollection to supervise the necessary GDI+ objects.

Points of Interest

The DisposableCollection class supports full collection semantics, so that you can, say, index in and remove items. However, I anticipate that the vast majority of all uses will only add items as in the above examples. It will throw an exception if you attempt to use any collection method after the DisposableCollection has been disposed. It will also clear its internal list of IDisposable objects, freeing them up to be garbage-collected. (Note that by that point, each collection item has already had its Dispose method called.)

A Word About "Using" in the .NET Framework 2.0

As you can see, if you look at the publicly available prerelease documentation for Visual Studio .NET 2005 on MSDN, Visual Basic .NET is picking up the Using statement. Moreover, multiple resources in the same Using block need not be of the same type. Thus, the following code is valid:

VB
Using f As New Font(FontFamily.GenericMonospace, _
         12, FontStyle.Bold), b As New Pen(Color.Red)
    e.Graphics.DrawLine(b, 5, 5, 25, 25)
    e.Graphics.DrawString("Hello", f, Brushes.Blue, 20, 30)
End Using

This is a welcome improvement to the language that makes the DisposableCollection obsolete in many scenarios. Unfortunately, as of the Beta 1 release of Visual Studio .NET 2005, the C# using statement appears to have not changed and still requires all resources in a single using block to be of the same type.

History

09/24/2004 - Initial release.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
I have over 10 years of full-lifecycle software development experience on a variety of large projects. I have a B.S. in Math from the University of Nebraska-Lincoln, a Masters in Software Engineering from Seattle University, and a Masters in Computer Science from the University of Maryland. I specialize in building and installing tools, frameworks, and processes that improve developer productivity and product quality. I am currently based in the Seattle area.

Comments and Discussions

 
GeneralAnother advantage of the Disposable Collection Pin
dsk30375-Oct-04 18:06
dsk30375-Oct-04 18:06 
GeneralRe: Another advantage of the Disposable Collection Pin
Scott McMaster6-Oct-04 9:00
Scott McMaster6-Oct-04 9:00 
GeneralNested using statements Pin
andrebrogli27-Sep-04 11:38
professionalandrebrogli27-Sep-04 11:38 
GeneralRe: Nested using statements Pin
Scott McMaster27-Sep-04 14:03
Scott McMaster27-Sep-04 14:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.