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!