Click here to Skip to main content
15,899,475 members
Please Sign up or sign in to vote.
4.67/5 (4 votes)
See more:
Okay, I'm confused on what to Dispose and when.
Below is a subroutine called from a loop. First time through it is okay, the second time through it throws a
System.Exception "Parameter is not valid" on the DrawString line.
But if I remove all the Dispose commands at the bottom I can call this subroutine a dozen times without error.

Obviously in this instance I can just remove the Dispose commands and move on but I want to understand when I should or shouldn’t call Dispose.
(After all I might be missing some Dispose calls elsewhere in my program.)

private void DrawRotatedText(Graphics Canvas, string text, Rectangle DestRect)
{
	//Create temp workspace
	Bitmap bmp = new Bitmap(500, 500, PixelFormat.Format64bppArgb);
	Graphics g = Graphics.FromImage(bmp);
	g.Clear(Color.White);

	//Write on it
	Font font = new Font("Arial", 12, FontStyle.Regular, GraphicsUnit.Pixel);
	Brush brush = Brushes.Black;
	StringFormat stringFormat = new StringFormat();
	stringFormat.Alignment = StringAlignment.Center;
	stringFormat.LineAlignment = StringAlignment.Center;
	g.DrawString(text, font, brush, (bmp.Width / 2), (bmp.Height / 2), stringFormat);

	//Rotate image here
	Bitmap bmp2 = Rotator.RotateImage(bmp, (360 - 45));

	// Set the transparency color key based on the upper-left pixel of the image.
	ImageAttributes attr = new ImageAttributes();
	attr.SetColorKey(bmp.GetPixel(0, 0), bmp.GetPixel(0, 0));

	// Draw the image using the image attributes.
	Rectangle SrcRect = new Rectangle((bmp2.Width / 2) - (DestRect.Width / 2),
		(bmp2.Height / 2) - (DestRect.Height / 2), DestRect.Width, DestRect.Height);
	Canvas.DrawImage(bmp2, DestRect, SrcRect.Left, SrcRect.Top, SrcRect.Width,
		SrcRect.Height, GraphicsUnit.Pixel, attr);

	//Tidy up
	bmp.Dispose();
	font.Dispose();
	brush.Dispose();
	stringFormat.Dispose();
	bmp2.Dispose();
	attr.Dispose();
	g.Dispose();
}


[edit]Corrected formatting[edit]
Posted
Updated 18-Dec-10 14:20pm
v4

Hi,

it is good practice to Dispose of objects that satisfy all these conditions:
1. they have a public Dispose() method
2. you don't need them anymore
3. you did cause their creation. This includes all "new Somethings()", all "CreateXxx()" results, and some specials such as Image.FromFile(); it excludes the objects you are borrowing, such as the Graphics you get from PaintEventArgs, the Brush you get from Brushes.Black, etc. There also is no need to Dispose of Controls that reside on a Form: when the Form gets closed, the Controls get Disposed of automatically.

there are two good reasons to call Dispose explicitly:
1. the object may contain unmanaged resources (e.g. memory blocks allocated outside the CLR)
2. the object may be expensive (e.g. use lots of memory)
Disposing it explicitly does whatever is necessary to free the resources (when unmanaged) or make them collectable (when managed).

it is also common practice to Dispose in reverse order, hence a=new A(), b=new B(), b.Dispose(), a.Dispose(); this may be relevant when b actually depends on a as in b=new B(a);

it may be wise to include null tests, as in if(b!=null) b.Dispose(); in case you are not sure b really got created (say in a finally block where the try part maybe didn't complete).

:)
 
Share this answer
 
v2
Comments
Dr.Walt Fair, PE 18-Dec-10 20:55pm    
Thanks, Luc! I thought I knew all about Dispose() but you taught me something.
Dalek Dave 23-Dec-10 20:12pm    
Good Answer!
Here is an application of Dispose techniques to your code snippet:

First, the problem with your code is this: the lack of exception handling. Basically, when disposeable resources are allocated, you need to wrap the rest of the code in try-finally block and dispose them in finally block. Better yet, use syntax candy of using block; you can allocate several instances of resources in a single using block. (Yes, this is just syntax candy: the documentation clearly states that using is functionally precisely equivalent to the try-finally block.) This way, your resources will be disposed even in the case of exception.

Secondly, you need to consider alternative of using of the Form's (and related component model's) disposable pattern. Allocating and disposing of resources is relatively expensive. Ask yourself, do you have any resource which could be re-used in your method DrawRotatedText? (If not, how about another, similar method?)
In fact, your brush variable is redundant, and its Dispose call is a mistake, because you're actually trying to dispose Brushes.Black; and font, attr, and imageFormat are all re-usable. So, you can promote these local variables to the position of your Form's class slots, allocate before showing the form and dispose from withing the Form's method Form.Dispose(Boolean) by overriding this method.
 
Share this answer
 
v2
Comments
Sergey Alexandrovich Kryukov 19-Dec-10 1:21am    
Could a person who voted this way explain to us what's wrong?
Dalek Dave 23-Dec-10 20:12pm    
Don't know why you got a downvote, it's a good answer.
Espen Harlinn 26-Feb-11 10:58am    
Good reply - a 5
Sergey Alexandrovich Kryukov 26-Feb-11 19:59pm    
Passions about Dispose...
Thank you, Espen.
--SA
The IDisposable.Dispose is used in one more case: when you need to control some action called at the moment of disposable. The moment of the destructor call is (in regular code not tricking GC) is normally out of your control.

In .NET, the rule of thumb is not writing destructors at all; there are exclusions, of course.

Example: you have some object which you create, call one method of it which takes a second or two then it is not needed anymore; and want to do it on UI thread. You need to make sure the application shows Hourglass cursor while application is busy with this method. There is a little problem here: you do not to forget to set this cursor back; you also don't want to get stuck with the Hourglass cursor is an exception is thrown.

Here is the technique: create object controlling mouse pointer: 1) in constructor, set up hourglass mouse pointer; 2) make it disposable, in Dispose, setup default mouse pointer or a pointer remembered at the moment of the constructor call, then use:

C#
using(WaitCursorIndicator controller = new WaitCursorIndicator(myControl) {
   //do your time-taking action
}


Please look at my Tips/Tricks article for detailed explanation:
Hourglass Mouse Cursor Always Changes Back to its Original Image. How?[^]

On the end of using block, default mouse pointer will be restored, even on exception. There are a lot of similar techniques like that.

Typically, IDisposable is useful if you take benefits of using block or
if you need a chain of dispose action going to the very top level, such as a form. (Criteria listed in previous answer should apply.)
 
Share this answer
 
v5
Comments
Sergey Alexandrovich Kryukov 19-Dec-10 1:21am    
Could a person who voted this way explain to us what's wrong?
Sergey Alexandrovich Kryukov 19-Dec-10 1:22am    
Also, see the last version of the Answer
Espen Harlinn 26-Feb-11 10:58am    
Good reply - a 5
Sergey Alexandrovich Kryukov 26-Feb-11 19:58pm    
Thank you.
--SA
Just for example, yet another use case of Dispose: see this:

Hourglass Mouse Cursor Always Changes Back to its Original Image. How?[^]
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900