views:

186

answers:

4

If you have a brush and pen as in:

Brush b = new SolidBrush(color);
Pen p = new Pen(b);

and dispose them like so:

b.Dispose();
p.Dispose();

How would you dispose it if it was:

Pen p = CreatePenFromColor(color) which would create the brush and pen for you? I can't dispose the brush inside this method, right?

Is this a method not to be used with disposable objects?

EDIT: What I mean is, how do you dispose the BRUSH?

+5  A: 

You still have to dispose it when you're done.

For example, you could call it like this:

using (Pen p = CreatePenFromColor(color))
{
    // do something
}

If a method returns an IDisposable object, it is your duty to dispose it.

[Edit] Now I got the question -- you are using the Pen(Brush b) constructor.

a. In this case, it seems that Pen does not need the Brush instance after constructor, so your method could look like this:

public Pen CreatePenFromColor(Color c)
{
    using (Brush b = new SolidBrush(c))
    { return new Pen(b); }
}

b. Why not simply use Pen(Color color)?

public Pen CreatePenFromColor(Color c)
{
    return new Pen(c);
}

c. (regarding the comment) If the Pen would hold a reference to the Brush internally, then you wouldn't be able to dispose it before you are finished with the Pen. In that case, I would go for a class which would do the job for me:

public class PenHelper : IDisposable
{
     private readonly Brush _brush;
     public PenHelper(Color color)
     {
         _brush = new SolidBrush(color);
     }

     public Pen CreatePen()
     {
         return new Pen(_brush);
     }

     public void Dispose()
     {
         _brush.Dispose();
     }
}

and then use it like this:

using (PenHelper penHelper = new PenHelper(Color.Black))
{
     using (Pen pen = penHelper.CreatePen())
     {
          // do stuff
     }
}

Disclaimer: IDisposable is not implemented according to guidelines, but rather for demonstration only. Also, the whole example is used only to show how to encapsulate a reference when needed. You should go for Pen(color) of course.

Groo
+1 for "why are people creating brushes to create pens from?!?"
Jason Williams
Thanks. In you example a, brush b would be disposed as soon as Pen is returned, right? If Pen had a reference to brush b inside, then it would throw an example? Just wondering.
Joan Venge
Thanks for the extended example.
Joan Venge
A: 

When a method hands off an IDisposable instance, it is simultaneously handing over the lifetime management responsibility.

It is now the caller's responsibilty to dispose of the object after use. If that object contains other IDisposable objects, by convention we must expect the container to properly dispose of its children when we dispose it - otherwise it would imply a bug in the container.

In your concrete example, you should expect the Pen to dispose of its internal Brush instance when you dispose it.

Mark Seemann
Colors are disposable too?
Joan Venge
No, Color is a struct.
Groo
@Joan Venge: 'Typo' - I corrected it concurrently with your comment...
Mark Seemann
I think that returning a reference to an IDisposable object does not automatically imply that you're handing off ownership. Transfer of ownership needs to be explicitly documented. For example, multiple view controls may have references to a disposable business object (and listen for a Disposing event), but none of them own it.
Wim Coenen
@wcoenen: I'm not saying that you couldn't think up a case where it wouldn't be the case - I'm just saying that it would be a horrible design. I consider any API that needs to 'explicitly document' anything to be failed.
Mark Seemann
+8  A: 

It is the job of the CreatePenFromColor method to dispose of the Brush instance. It's not obvious at a glance but if you dig into the implementation of the Pen class you will see that it does not hold onto the passed in Brush instance. Instead it just uses it to calculate a few values. So there's no reason for the Brush instance to live beyond the call to CreatePenFromColor and the method should be disposing of the instance.

JaredPar
Thanks Jared, I didn't know that.
Joan Venge
That's not necessarily true. the Pen constructor passes the brush's handle to `GdipCreatePen2`. I don't know whether `GdipCreatePen2` needs the brush to stay alive (the function is barely documented), but I would guess that it does. Remember that the brush could be a `TextureBrush` with an image, and you wouldn't want the Pen to make a separate copy of the image in memory so that you could dispose the brush.
SLaks
@Slaks, GdipCreatePen2 AFAIK does not require it to stay alive. I dug through the very limited documentation and it's only needed to setup the pen, not maintain it.
JaredPar
+2  A: 

Your problem has no general solution.

In your specific example, it's not a problem, because Pen has a constructor that takes a Color directly.

Some classes will dispose their constructor parameters themselves (especially Stream-related classes); check each class in Reflector.

If the class you're returning inherits from Component, you could add a handler to its Disposed event.

If the class you're returning isn't sealed, you could create an inherited version that disposes the object you created it from as well.

Finally, if you really wanted to, you could create a wrapper class that contains the object you're returning and disposes the constructor parameter. However, that would be very confusing and I would not recommend it.

SLaks
Thanks, I didn't know Pen could take a Color directly. It's funny because I see alot of code creating the brush and pen separately and then just using the Pen for painting.
Joan Venge
Then you should accept this answer.
SLaks
Yes, it does. There just isn't a clean general solution to it.
SLaks