views:

164

answers:

3

I'm currently writing a fairly complex paint method for a user control, involving a fair amount of drawing code. I know that all GDI+ resources need to be properly disposed so I wrap each of those in a using block.

But when I noticed that I used three using blocks for three different SolidBrushes I wondered whether I couldn't just re-use them. Create a SolidBrush, draw with it, assign a different color, draw something else, etc. And put a Dispose() at the end.

Is such a thing advisable or am I thinking too hard here? I don't particularly like too many using blocks nested in each other as well. While a nice pattern it hinders readability at times.

+1  A: 

Re-using GDI objects is not bad in itself. What is bad is when there are too many GDI objects in existence at one time than your graphics card GDI can handle.

I had earlier faced a problem as a result of caching a dashed pen and some brushes. My colleague's code (running within the same WM_PAINT) had no problems at all even though it did not cache any objects! Only my oversmartness was causing GDI to choke up and throw an OutOfMemoryException (they probably mean out of memory on the graphics card).

Vulcan Eager
Yes. You are right. I've corrected my post. But GDI+ objects are wrappers over GDI handles and I think the system could run out of handles.
Vulcan Eager
+4  A: 

Well, re-using is an optimization and it is probably premature and therefore: Yes it is a bad practice. I would wait for a clear performance problem to surface and then look for the bottleneck. You would be trading some (unknown) performance gains for the rapidly increasing complexity of managing the state of those components.

On a side note, one pretty much accepted form of nesting using-blocks looks like this:

 using (var a = ...)
 using (var b = ...)
 using (var c = ...)
 {

 }
Henk Holterman
Oh, that one is nice. Didn't really think of that. And it even survives Auto-formatting and StyleCop.
Joey
nice using chain "do-da". Didn't know you could do that.
Jon
Jon, it's by the same syntax rule as `if(c) b;` vs `if(c) { b; }` and with a different indentation style. It is catching on.
Henk Holterman
Henk: However, not all statements follow that rule. While loop and conditional constructs allow statements *or* blocks, some things, most notably `try`, `catch` and `finally` explicitly expect blocks. So it's not necessarily obvious that this works :)
Joey
Johannes, I know it isn't obvious, but knowing the rules helps a lot in using this properly.
Henk Holterman
A: 

I think there is nothing bad with this practice. But i think you can reuse the created Brushes. In my own UserControls, if i use Brushes i store them in a local variable of the UserControl and dispose them of when i dispose the UserControl.

public class MyUserControl : UserControl{

  private SolidBrush _brush;

  public MyUserControl() {
    _brush = new SolidBrush(Color.Red);
  }

  protected override void OnPaint(PaintEventArgs e){
    // Draw with the brush;
  }

  protected override void Dispose(bool disposing){
    // other Dispose logic
    if (_brush != null) {
      _brush.Dispose();
    }
  }
}
Jehof