Don't Throw Out the System Brushes

Introduction

In a recent MSDN forum question an interesting topic came up that may not be obvious at first glance. The issue was related to disposing of a system brush. This article will explain the issue and discuss which brushes should be thrown out (disposed) and which should not.

Problem Description

The problem the user was experiencing was related to using a Brush in a method that would draw to a PictureBox and upon calling the method a second time it would throw an exception. The scenario is best demonstrated using a simplified code example.



      Private Sub  Draw(g As  Graphics)
                    Dim fillBrush As Brush = Brushes.Black  
               
                    Try      
                        'use the brush to draw      
                        g.FillRectangle(fillBrush,       New  Rectangle(0, 0, 10, 10))  
                    Catch ex As Exception  
                        MsgBox(ex.Message)      
                    Finally      
                        fillBrush.Dispose()      
                    End Try  
               
      End Sub

In this example a Brush object is created and assigned the system brush System.Brushes.Black. After using the brush it is being disposed of, as is typically recommended for Brush, Pen, and other similar objects. The second time this method is called the following exception is generated.

Understanding the Problem

The exception is generated as a result of trying to use the fillBrush the second time this method is called. You might find this odd since a new brush is created each time the method is called, but the underlying issue is actually with Brushes.Black.

The fillBrush is simply acting as a reference or pointer to the system brush Brushes.Black rather than a custom user created brush. When fillBrush.Dispose() is called it is disposing the static system brush such that it is not available for future use.

Using Visual Studio we can dig into the fillBrush a bit more and see that the IntPtr, NativeBrush is initially set to a value when the method is first called, but after disposing, it is set to 0.

     

Solution

To correct this issue, simply remove the fillBrush.Dispose() call. While this seems like a trivial solution, it may be confusing to others who may review your code and expect to see the brush disposed after using it.

Suggestions

To avoid any confusion it may be a good idea to directly use the system brush. Modifying the above example to directly use the system brush would look like:

Private Sub  Draw(g As Graphics)
  
    Try
        'use the system brush to draw
        g.FillRectangle(Brushes.Black, New  Rectangle(0, 0, 10, 10))
    Catch ex As Exception
        MsgBox(ex.Message)
    End Try
 
End Sub

Alternatively a custom brush could be created, such as the following example, in which case Dispose should still be called.

Private Sub  Draw(g As Graphics)
    Dim fillBrush As New  SolidBrush(Color.Black)
  
    Try
        'use the custom brush to draw
        g.FillRectangle(fillBrush, New  Rectangle(0, 0, 10, 10))
    Catch ex As Exception
        MsgBox(ex.Message)
    Finally
        fillBrush.Dispose()
    End Try
  
End Sub

Summary

While the general recommendation is to dispose brushes, pens, and related objects, you must be careful and first understand what you are throwing out. If you are dealing with a system object, leave it alone and let the system take care of it. If you are working with your own custom objects, don't forget to throw them out (dispose them) when you are done or they may pile up and create a smelly problem.

Happy coding!