How to handle disposable objects we don't have a reference to?
If you have a brush and pen as in:
Brush b = new SolidBrush(color);
Pen p = new Pen(b);
开发者_JAVA百科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?
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.
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.
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.
One of my peeves with many of the Graphics-related classes is that there is no consistent pattern for handling such issues. What is really needed is a means of implementing partial reference counting. Not in the COM style, where passing around references requires constant bumping of reference counts, but in a means by which, given an IDisposable graphics object, one can request another instance which shares the same underlying resource. The resources themselves would be encapsulated in a shared object with a reference counter. Creating another referencing instance would increment the counter; calling Dispose on a referencing instance would decrement it. This would avoid 95% of the overhead of reference counting, while retaining 99% of the benefit.
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.
精彩评论