Click here to Skip to main content
Click here to Skip to main content

Diposer for GDI+ resources (Pen, Brush, ...)

By , 23 Oct 2009
 

Introduction

The draw resource classes found inside the System.Drawing namespace (Pen, SolidBrush, ...) are actually wrapping the underling native Windows GDI resources. Like all system resources, their amount is limited, and so they should be returned to the Operating System as soon as possible.

That's why .NET documentation tells you to call the Dispose() method on Pens, Brushes etc., as soon as they are not used anymore.

Background

But .NET is a managed environment and has a garbage collector, then why do we have to manually release resources? Consider the following usual paint code:

protected override void OnPaint(PaintEventArgs e)
{
    Pen myPen1 = new Pen(Color.Black, 3);
    Pen myPen2 = new Pen(Color.Lime, 3);
    SolidBrush myBrush1 = new SolidBrush(Color.Red);
    SolidBrush myBrush2 = new SolidBrush(Color.Lime);

    // ....
    // use myPenX and myBrushX for drawing
    // ...
}

Pen and SolidBrush are internally holding unmanaged native Win32 GDI resources (HBRUSH, HPEN etc.). These are precious Windows system resources and should be released as soon as possible. When OnPaint() exits, the only references to myPenX and myBrushX are gone, so the .NET garbage collector will release the instances sometime later. This will, of course, also release the underlying native handles. But the point is, sometime later. For the time span between the last reference gone and the garbage collector releasing the unused instances, the underlying native resources are occupied although not in use anymore. This can be a problem on heavy system load situations. And, like all resources, we should use them not more than necessary, and return them as soon as we do not need them anymore.

So, we have to call Dispose() on all Pens, Brushes, etc.:

protected override void OnPaint(PaintEventArgs e)
{
    Pen myPen1 = new Pen(Color.Black, 3);
    Pen myPen2 = new Pen(Color.Lime, 3);
    SolidBrush myBrush1 = new SolidBrush(Color.Red);
    SolidBrush myBrush2 = new SolidBrush(Color.Lime);

    // ....
    // use myPen and myBrush for drawing
    // ...

    myPen1.Dispose();
    myPen2.Dispose();
    myBrush1.Dispose();
    myBrush2.Dispose();
}

If you have a complicated drawing routine incorporating many pens and brushes, calling Dispose() on all instances can be a tedious and error prone task. You easily add a new brush in the middle of your code and forget to call Dispose() on it before method exit. And be aware: if an exception is thrown somewhere in your drawing code, the control flow can jump out of OnPaint() without running to its end. So, the Dispose() of your instances will not be called at all.

C# provides the using statement for this situation:

protected override void OnPaint(PaintEventArgs e)
{
    using (Pen myPen1 = new Pen(Color.Black, 3))
    using (Pen myPen2 = new Pen(Color.Lime, 3))
    using (SolidBrush myBrush1 = new SolidBrush(Color.Red))
    using (SolidBrush myBrush2 = new SolidBrush(Color.Lime))
    {
        // use myPenX and myBrushX for drawing
    }
    // here all resources created inside using() are diposed,
    // also in case of an exception or return statement
}

This solves the problem perfectly for simple OnPaint() methods. But if there is more complicated painting involving different paint resources depending on the control's state, we have to create all possibly used resources before painting:

protected override void OnPaint(PaintEventArgs e)
{
    using (Pen myPen1 = new Pen(Color.Black, 3))
    using (Pen myPen2 = new Pen(Color.Lime, 3))
    using (SolidBrush myBrush1 = new SolidBrush(Color.Red))
    using (SolidBrush myBrush2 = new SolidBrush(Color.Lime))
    {
        if ( some condition )
        {
            // use myPen, myBrush1 and myBrush2, myPen2 is not used
            if ( some other condition )
            {
                // use myPen2
            }
        }
        else
        {
            // use myPen1 and myBrush1 for drawing,
            // myPen2 and myBrush2 are never used
        }
    }
    // here all resources created inside using()
    // are diposed, also in case of an exception or return
}

Of course, this is not a big deal if only one brush or pen is unnecessarily created. I do visualizations for industrial processes, and there we use sophisticated user controls involving a lot of complicated painting using many different resources. And, there are two big 1600x1080 screens showing many of those controls on the same time. All the needless draw resources created have a measurable impact on the system performance. To avoid this, we would end with something like this:

protected override void OnPaint(PaintEventArgs e)
{
    using (Pen myPen1 = new Pen(Color.Black, 3))
    using (SolidBrush myBrush1 = new SolidBrush(Color.Red))
    {
        if ( some condition )
        {
            using (SolidBrush myBrush2 = new SolidBrush(Color.Lime))
            {
                // use myPen1, myBrush1 and myBrush2
                if ( some other condition )
                {
                    using (Pen myPen2 = new Pen(Color.Lime, 3))
                    {
                        // use myPen2
                    }
                    // here myPen2 is disposed
                 }
            }
            // here myBrush2 is disposed
        }
        else
        {
            // use myPen1 and myBrush1 for drawing, myPen2 and myBrush2 are never used
        }
    }
    // here myPen1 and myBrush1 are disposed
}

So far, so good. But imagine the code we are ending up with if there are 6 conditions and 12 draw resources, some of them used in all control paths, some in only one, some in three of them, and so on. The resulting construct of nested using statements is hard to read and even harder to maintain. If the drawing code changes and a resource used before only in one control path is newly used in another control path too, we have to rearrange the whole code.

Helper class to dispose drawing resources on method exit

I have a strong C++ background, and in C++, it is a best practice to encapsulate resources in objects to get them released as soon as they go out of scope. This is especially important to make code exception safe. So, I ported the C++ approach to C#: have a helper class releasing resources.

using System;
using System.Collections.Generic;

class Disposer : IDisposable
{
    private List<IDisposable> m_disposableList = 
            new List<IDisposable>();
    private bool m_bDisposed = false;

    // default ctor
    public Disposer()
    {
    }

    public void Add(IDisposable disposable)
    {
        if (m_bDisposed)
        {
            // its not allowed to add additional items
            // to dispose if Dispose() already called
            throw new InvalidOperationException(
              "Disposer: tried to add items after call to Disposer.Dispose()");
        }
        m_disposableList.Add(disposable);
    }

    #region IDisposable members
    public void Dispose()
    {
        if (!m_bDisposed)
        {
            foreach (IDisposable disposable in m_disposableList)
            {
                disposable.Dispose();
            } 
            m_disposableList.Clear(); 
            m_bDisposed = true;
        }
    } 
    #endregion
}

All drawing resource classes in the System.Drawing namespace implement the IDisposable interface. It declares a method, Dispose(). For details, see the MSDN documentation on IDisposable. We add all object instances to be disposed to an instance of Disposer, which iterates the internal list and calls Dispose() on all entries. Be aware that this code is not thread safe. For this, m_disposableList and m_bDisposed would need to be protected with a lock(). The intended use case for this helper class is inside user controls, where all members have to be accessed from the thread which initially created the control anyway.

Usage of the Disposer helper class

Now, the OnPaint() method is changed to use the Disposer helper class:

protected override void OnPaint(PaintEventArgs e)
{
    using (Disposer drawResDisposer = new Disposer())
    {
        Pen myPen1 = new Pen(Color.Black, 3);
        drawResDisposer.Add(myPen1);
        SolidBrush myBrush1 = new SolidBrush(Color.Red);
        drawResDisposer.Add(myBrush1);

        if ( some condition )
        {
            SolidBrush myBrush2 = new SolidBrush(Color.Red);
            drawResDisposer.Add(myBrush2);
            // use myPen1, myBrush1 and myBrush2
            if ( some other condition )
            {
                Pen myPen2 = new Pen(Color.Yellow, 3);
                drawResDisposer.Add(myPen2);
                // draw using myPen2
            }
        }
        else
        {
            // use myPen1 amyBrush1 for drawing,
            // myPen2 and myBrush2 is never used
        }
        // here all resources added to drawResDisposer
        // in any control path are disposed
    }

Just add every instantiated drawing object to the Disposer, drawResDisposer, and on exit of the code block surrounded by using {}, drawResDisposer.Dispose() is called automagically, which calls the Dispose() of all the instances added to it. No need to know which of the draw resources where actually needed and created. Just add them to the disposer, use them, and forget about them. I think this is a much cleaner and easier to maintain code structure.

The Disposer class can also be used for every other class encapsulating native and unmanaged resources. As long as the class implements the IDisposable interface.

I am a fan of one single kind of programmer laziness only: Don't do things manually which can be done by the compiler or the runtime automatically.

Improving the Disposer with WeakReference

In advanced user controls, we should not create all drawing resources on each call of OnPaint(). Painting occurs quite frequently in situations like resizing. It is a waste of resources to create a pen every time it is used and then hand it over to the garbage collector for destruction directly. Each drawing resource should be created on first use, and disposed inside the control's Dispose() method. In other words, we create a singleton for each different drawing resource type used for painting. This way, the resources are held by the control during its lifetime, but this is still better than constructing and destroying the same drawing resources over and over again. But, this approach makes the problem even worse: the resources are now created and destroyed in different methods of the control class, so it is much harder to get the Dispose() of each resource called inside the control's Dispose() method. If we fail to dispose the disposer instance when the control gets destroyed, the internally existing references to the IDisposable instances stop the garbage collector from freeing them. Less than better...

To make the disposer helper class more useful in such situations, it is changed to use the .NET System.WeakReference class. It allows the garbage collector to free an object although there is still a reference, a weak one. See the MSDN documentation for details. This class is made for such kind of situations: a reference to an object which can be used to dispose it but does not count itself as a reference for the garbage collector.

using System;
using System.Collections.Generic;

class Disposer : IDisposable
{
    private List<WeakReference> m_disposableList = 
            new List<WeakReference>();
    private bool m_bDisposed = false;

    // default ctor
    public Disposer()
    {
    }

    public void Add(IDisposable disposable)
    {
        if (m_bDisposed)
        {
            // its not allowed to add additional items
            // to dispose if Dispose() already called
            throw new InvalidOperationException(
              "Disposer: tried to add items after call to Disposer.Dispose()");
        }
        m_disposableList.Add(new WeakReference(disposable));
    }

    #region IDisposable members
    public void Dispose()
    {
        if (!m_bDisposed)
        {
            foreach (WeakReference weakRef in m_disposableList)
            {
                try
                {
                    if (weakRef.IsAlive)
                    {
                        // sadly there is no generic version of WeakReference
                        // WeakReference<IDisposable> would be nice...
                        IDisposable strongRef = (IDisposable)weakRef.Target;
                        // strongRef is null if weakRef.Target already disposed
                        if (strongRef != null)
                        {
                            strongRef.Dispose();
                        }
                    }
                } 
                catch (System.InvalidOperationException ex)
                {
                    // weakRef.Target already finalized
                }
            }
        } 
        m_disposableList.Clear(); 
        m_bDisposed = true;
    }
    #endregion
}

Here is the usage of the improved class inside a control:

class MyControl : UserControl
{
    private Disposer m_Disposer = new Disposer();

    private Pen m_Pen1 = null;
    private Pen1
    {
        get
        {
            if (m_Pen1 == null)
            {
                m_Pen1 = new Pen(Color.Lime, 5);
                m_Disposer.Add(m_Pen1);
            }
            return m_Pen1;
        }
    }

    private SolidBrush m_Brush1 = null;
    private Brush1
    {
        get
        {
            if (m_Brush1 == null)
            {
                m_Brush1 = new SolidBrush(Color.Red);
                m_Disposer.Add(m_Brush1);
            }
            return m_Brush1;
        }
    }

    //
    // ... many other pens, brushes, fonts, we draw a copmlicated control
    //

    protected override void OnPaint(PaintEventArgs e)
    {
        // ...
        // use the same singleton on every call
        e.Graphics.DrawLine(this.Pen1, point1, point2);
        e.Graphics.FillRectangle(this.Brush1, rect);
        // ...
    }

    #region IDisposable members
    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (components != null)
            {
                components.Dispose();
            }
            m_Disposer.Dispose()
            base.Dispose(disposing);
        }
    }
    #endregion

    //
    // ...
    //
}

All you have to is add the lines shown in bold. If you forget the call to m_Disposer.Dispose(), the garbage collector will take care of the draw resources. The references held inside the disposer class do not count for the garbage collector anymore. This is exactly what we want.

Points of interest

This possible usage of the using keyword is often overseen:

// myType is any type implementing IDisposable
using (myType myVar = new myType())
{

    // ...
    // code here making use of myVar
    // ...
}

If the code block following using() is left on any path, including an exception, a return in the middle etc., myVar.Dispose() is called implicitly. The needed calls are inserted by the C# compiler. The only restriction for types used in using() is that they implement IDisposable.

The using statement is actually just syntactic sugar which is extended by the C# compiler to the following code. You can see this if you inspect your binary assembly with Reflector:

try
{
    // myType is any type implementing IDisposable
    myType myVar = new myType();

    // ...
    // code here making use of myVar
    // ...

}
catch (System.Exception ex)
{

}
finally
{
    myVar.Dispose();
}

Conclusion

Although no resources will really be leaked by not calling Dispose() on GDI wrapper classes, it's a good habit to do so. This way, they are released when they are not needed anymore, and not sometime later when the garbage collector is run the next time.

Better idea?

I'm aware of the fact that this is a C++ approach. I'm relatively new to C#, but did C and C++ since more than a decade before. So, if you have a more "C#-ish" way to do this, please tell me.

History

  • 07/07/2009 - Initial version.
  • 10/13/2009 - WeakReference version added, some minor text additions.
  • 10/22/2009 - Reworked code samples to better show the intended use case.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Joerg Blattner
Software Developer (Senior)
Switzerland Switzerland
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberEarnesto Developez15 Dec '11 - 11:00 
This is a counter measure to all the hate from the automated garbage collectors cultists in .NET. I'm always for manual cleanup and smart resource management... as I write .CPP Wink | ;)
GeneralMy vote of 1memberrrodgers3.142 Dec '09 - 7:25 
Use "using"
GeneralRe: My vote of 1memberJoerg Blattner8 Dec '09 - 7:08 
In my opinion, the article clearly states the problems with plain using {}.
 
If you ever write a complicated user control with a lot of control state depending paint code you will discover what I mean.
You will also see the performance impact of creating the same paint resources over and over on each call of OnPaint() if you have a big 1600 x 1050 screen showing >50 of your user controls at the same time. Especially if your PC has other things to do in the background than garbage collecting thousands of paint resources per second. Just try it out.
GeneralMy vote of 1memberwinSharp9320 Oct '09 - 5:00 
Use using!
Or let the GC do the work / using WeakReferences only brings in additional complecity IMHO and is redundant.
General*MY* vote of 1memberIlíon24 Oct '09 - 14:15 
winSharp93 wrote:
Use using!

The article explains the problem with using using, and which problem this helper class sets to solve.
GeneralMy vote of 1memberPrzemyslaw Wlodarczak19 Oct '09 - 23:12 
There is no added value in Disposer class. Plain using statements are much cleaner
General*MY* vote of 1memberIlíon24 Oct '09 - 14:15 
Przemyslaw Wlodarczak wrote:
There is no added value in Disposer class. Plain using statements are much cleaner

The article explains the problem with using using, and which problem this helper class sets to solve.
Generalstandard colorsmvpLuc Pattyn15 Oct '09 - 2:02 
A lot of popular GDI objects are available without the need to create nor dispose them:
- class Pens offers pens with width=1.
- class Brushes contains a lot of SolidBrush instances.
 
So the first attempt to solve the Dispose requirements would be to use those whenever possible.
 
Hence, the article really should use different examples, say Fonts and pens with a width larger than 1.
 
Smile | :)
 
Luc Pattyn

I only read code that is properly indented, and rendered in a non-proportional font; hint: use PRE tags in forum messages

Local announcement (Antwerp region): Lange Wapper? Neen!


GeneralRe: standard colorsmembersupercat916 Oct '09 - 7:29 
Luc Pattyn wrote:
Hence, the article really should use different examples, say Fonts and pens with a width larger than 1.

 
Or better yet, code which may (depending upon what's being drawn) either use a stock object or a newly-created one. Which is nicer (bearing in mind that one Disposer object can handle many brush, font, pen, and other objects:
  Using Dispos as New Disposer
    Dim BR1 as Brush,BR2 as Brush
 
    If Color1=Color.Black then
      BR1 = Brushes.Black
    Else
      BR1 = New SolidBrush(Color1)
      Dispos.Add(BR1)
    End If
    If Color2=Color.Black then
      BR2 = Brushes.Black
    Else
      BR2 = New SolidBrush(Color2)
      Dispos.Add(BR2)
    End If
    .. Now do stuff with BR1 and BR2
  End Using
or, if not using Disposer:
  Dim DisposBR1 = False
  Dim DisposBR2 = False
  Try
    If Color1=Color.Black then
      BR1 = Brushes.Black
    Else
      BR1 = New SolidBrush(Color1)
      DisposBR1 = True
    End If
    If Color2=Color.Black then
      BR2 = Brushes.Black
    Else
      BR2 = New SolidBrush(Color2)
      DisposBR2 = True
    End If
    .. Now do stuff with BR1 and BR2
  Finally
    If DisposBR1 Then BR1.Dispose
    If DisposBR2 Then BR2.Dispose
  End Try
I would think approach #1 would be far less error-prone, though it might be improved by adding a generic function to Disposer which would add its argument and return it (allowing something like:
  BR1 = Dipos.Add(New SolidBrush(Color1))

GeneralMy vote of 1membercpw999cn14 Oct '09 - 17:46 
I prefer to use 'using' instead of this.
GeneralRe: My vote of 1membersupercat916 Oct '09 - 13:17 
cpw999cn wrote:
I prefer to use 'using' instead of this.

 
Suppose you're writing a paint routine for an object which will often use pre-existing graphic objects, but which may need to create temporary ones. Wrapping the routine with a "Using xxx as Disposer" clause and then adding to the Disposer any temporary objects which are created, seems cleaner than any other approach I can think of. What approach would you suggest, given that it's not possible to execute code inside a "Using" block without creating an object before the code starts and disposing the object after the code ends?
 
When each temporary object is created, the code that creates it will know that the lifetime of the object will be temporary. Placing all of the code for object disposition at the point of object creation seems much safer than requiring cleanup code to know which objects are temporary and which are persistent.
GeneralMy vote of 1memberseeblunt14 Oct '09 - 13:31 
Ignorant
GeneralIgnorance is dangerous.memberseeblunt14 Oct '09 - 13:31 
GDI objects are fast to create/destroy. No need to cache. In fact , it is vital to dispose of the GDI Objects immediately when done using them.
They are a System Resource.
End of story.
 
using (gdiobject)
{
...
}
GeneralRe: Ignorance is dangerous.memberJoerg Blattner14 Oct '09 - 14:50 
The whole approach was inspired by the books "Effectice C#" and "More Effective C#" and better performance proofed on heavy GDI+ drawing situations.
GeneralRe: Ignorance is dangerous.memberseeblunt14 Oct '09 - 15:55 
I would seriously question the authors of these books regarding any implied or stated concepts related to cache of GDI objects.
Any performance improvements (would probably be miniscule) would evaporate when System Resources are not released and become scarce.
I have seen this happen many times.
For a graphic example a small change in the code resulted in large CPU utilisation improvements and I am not even sure why.
http://www.codeproject.com/Messages/3181845/Tidy-up-the-code-equalsequals-Fix-CPU-utilisation.aspx
GeneralMy vote of 1memberHeywood14 Oct '09 - 11:29 
useless functionality
GeneralMy vote of 2memberocccy17 Aug '09 - 20:50 
I can't see any reason, why I should use something like a "Disposer": Neither it saves lines of code, nor it guaranties, that all resources will be released (instead of calling obj.Dispose() I must call xxxDisposer.Add(obj))...So what's the advantage of the Disposer??
GeneralRe: My vote of 2memberJoerg Blattner27 Aug '09 - 2:23 
I like it better, because I can call xxxDisposer.Add() directly after creating every GDI object to dispose and then forget about it.
If I have to call obj.Dispose() for each single object, it's somewhere else in the code.
I did some complicated user controls with lot of conditional draw code in OnPaint() and subroutines inside OnPaint() which is only executed in certain states of the control. Of course the GDI objcets shall also created only if needed. I like it better than have using {} or obj.Dispose() all over my code. Especially when refactoring. And I find it much easier to get it exception safe.
 
If course it's not "better" or faster, but in my eyes this approach results in a much cleaner code structure. It's syntactic sugar.
If your OnPaint() method has 10 lines of codes and uses 3 draw objects, it's of course not worth the effort.
GeneralRe: My vote of 2memberHeywood14 Oct '09 - 11:26 
how is your approach cleaner than this?
 
using (Pen pen = new Pen(foreColor))
using {Brush forebrush = new SolidBrush(backColor))
using{ Brush backBrush = new SolidBrush(foreColor))
{
... use resources
}
 

You just use using. You don't have to remember to dispose the objects, you don't need to add the items to a "helper" object... I don't get it. my vote of 1.
GeneralWhy it's usefulmembersupercat915 Oct '09 - 7:58 
Heywood wrote:
how is your approach cleaner than this?

 
Suppose you may wish to create foreBrush in one of two ways, and the code that uses it will be the same regardless of how it's created. The only ways I can see to accomplish that with 'using' would be to either write a separate function to perform the object creation one of two ways (and call that function from the object-creation part of the 'using' statement) or else to move all the code that acts upon the object to a separate function which is called by separate 'using' statements. In many circumstances, the latter approach will be downright disgusting; the former approach might not be too evil, but it won't always work.
 
For example, suppose you want to draw something using either a default font (which is kept in a control's class field) or a named font. If one is using a named font, one must create it and then dispose it. If one is using the default object, one must not dispose it. It would seem the disposer class would make things easy:
  using myDisposer as new Disposer
  {
    dim myFont as Font
    if String.NullOrEmpty(thingie.fontname)
      myFont = theDefaultFont
    else
    {
      myFont = New Font(whatever properties)
      myDisposer.Add(myFont)
    }
    ... Now draw stuff using MyFont
  }
If one weren't using something like Disposer, one would have to use flags to keep track of which objects needed to be disposed. With MyDisposer, it's easy.
GeneralUse WeakReferencememberNiel M.Thomas13 Jul '09 - 21:12 
This approach could be used with Managed Direct X.
If you want to ensure that objects are disposed in the right order, or at all.
Instead of using a list with direct referene to the objects, you should look at a list of WeakReference's:
List<WeakReference> myGarbage = new List<WeakReference>(); 
Before calling dispose you should test if the object is collected using the IsAlive property.
 
[With best regards ]
[Niel M. Thomas ]
 


GeneralRe: Use WeakReferencememberJoerg Blattner23 Jul '09 - 9:39 
Yes, using WeakReference would work too. But I cant see any advantage of doing so.
If the disposer class is used as described in the article, Dispose() of all contained references is called at the same point as if it would be when called manually. But in an exception save way and with a (in my opinion) more readable code structure. Compared to wrapping each GDI object with it's own using {} statement.
The purpose of WeakReference is to allow the GC to trash an object altough someone is still knowing it. This situation cant happen here.
 
Another point is WeakReference would brake strict compile time type safety. Yes, I know, it's kind of a fetish for a longtime C++ programmer Wink | ;) We would have to write something like:
 
private List<WeakReference> m_disposableList = new List<WeakReference>();
 
public void Dispose()
{
    if (!m_bDisposed)
    {
        foreach (WeakReference current in m_disposableList)
        {
            if (!current.IsALive)
            {
                // target already finalized
                continue;
            }
            // we have a plain System.Object here, compile time type safety is lost
            IDisposable disposable = current.Target as IDisposable;
            if (disposable == null)
            {
                // current WeakReference target does not implement IDisposable
                continue;
            }
            disposable.Dispose();
        } 
        m_disposableList.Clear(); 
        m_bDisposed = true;
    }
} 
 
Further, using WeakReference needs secutity permission for unmanaged code. That's not allowed on all of our installations.
 
Am I missing the point?
 
Regards
Joerg
 
[Edit]
Typo in code sample
GeneralMore concisely and less error prone would be to just put a 'using' on every IDisposable unmanaged resource that you create ...memberHightechRider7 Jul '09 - 21:11 
e.g.
 
                
                using (var myPen1 = new Pen(Color.Black, 1))
                using (var myPen2 = new Pen(Color.Lime, 1))
                using (var myBrush1 = new SolidBrush(Color.Red))
                using (var myBrush2 = new SolidBrush(Color.Lime))
                {
                    // ....
                    // use myPen and myBrush for drawing
                    // ...
                }
 
So no need for another class to track these objects, no need to remember to add them to that object and if during code reviews you see a Pen, Brush, Bitmap, ... being created and it isn't in a using() statement and there isn't a comment there to explain why it's needed outside the current scope then you can discuss with the author and get a using() or comment added as appropriate.
GeneralRe: More concisely and less error prone would be to just put a 'using' on every IDisposable unmanaged resource that you create ...memberJoerg Blattner7 Jul '09 - 21:56 
Yes, for trivial painting routines that's of course true.
I created the class described inside the article while developing some complicated user controls with large OnPaint() methods.
There you often have parts painted only in certain states of the control. So the paint resources shall also be allocated only if needed.
 
Usage of using() for each individual GDI resource wrapper would lead to the following code structure:
 
using (Pen myPen1 = new Pen(Color.Black, 1))
{
    
    // draw with myPen1

    if (Condition1)
    {
        using (Pen myPen2 = new Pen(Color.Yellow, 1))
        {
            
            // draw with myPen2

            if (Condition2)
            {
                using (Pen myPen3 = new Pen(Color.Red, 1))
                {
                    
                    // draw with myPen3

                }
            }
        }
     }
}

GeneralRe: More concisely and less error prone would be to just put a 'using' on every IDisposable unmanaged resource that you create ...membersupercat915 Oct '09 - 8:14 
Joerg Blattner wrote:
There you often have parts painted only in certain states of the control. So the paint resources shall also be allocated only if needed.

 
I wouldn't consider the above code structure to be objectionable. As a better example, you should consider a control that e.g. has to do a lot of stuff with what may be either a persistent object or a specially-created one. In the latter situation, the object must be disposed, while in the former it must not. While one could manually use a flag to keep track of whether the object needs to be disposed and take care of it in a 'finally' block if so, I would think the Disposer object makes things much cleaner and less prone to mistakes.

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

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 23 Oct 2009
Article Copyright 2009 by Joerg Blattner
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid