Finally The Truth About "using" and Dispose()
The Problem
During the good chat with some fellow students last night, the top of whether or not "using" should be used over an explicit Dispose() method call when using objects like Graphics came up.
Now, this one has been bugging me for some time, and I have never actually sat down to investigate it, so I thought I should. I have been told on several occasions that I should use "using", but when questioning why, I get no real answer that makes any sense. Seems like a classic "every knows the best practice but doesn't understand the practice or why its best" scenario!
So, I made some very small code samples, one using "using" the other using Dispose(). Here are the samples FYI:
"using" Code
1: private void Form1_Load(object sender, EventArgs e)
2: {
3: using (Graphics g = Graphics.FromHwnd(this.Handle))
4: {
5: MessageBox.Show("this is between the graphics instantiation and disposal");
6: }
7: }
Dispose() Code
1: private void Form1_Load(object sender, EventArgs e)
2: {
3: Graphics g = Graphics.FromHwnd(this.Handle);
4: MessageBox.Show("this is between the graphics instantiation and disposal");
5: g.Dispose();
6: }
As you can see, nothing fancy! And here are the results (intermediate language - "IL") courtesy of ILDASM:
"using" IL
1: .method private hidebysig instance void Form1_Load(object sender,
2: class [mscorlib]System.EventArgs e) cil managed
3: {
4: // Code size 36 (0x24)
5: .maxstack 1
6: .locals init ([0] class [System.Drawing]System.Drawing.Graphics g)
7: IL_0000: ldarg.0
8: IL_0001: call instance native int [System.Windows.Forms]System.Windows.Forms.Control::get_Handle()
9: IL_0006: call class [System.Drawing]System.Drawing.Graphics [System.Drawing]System.Drawing.Graphics::FromHwnd(native int)
10: IL_000b: stloc.0
11: .try
12: {
13: IL_000c: ldstr "this is between the graphics instantiation and dis"
14: + "posal"
15: IL_0011: call valuetype [System.Windows.Forms]System.Windows.Forms.DialogResult [System.Windows.Forms]System.Windows.Forms.MessageBox::Show(string)
16: IL_0016: pop
17: IL_0017: leave.s IL_0023
18: } // end .try
19: finally
20: {
21: IL_0019: ldloc.0
22: IL_001a: brfalse.s IL_0022
23: IL_001c: ldloc.0
24: IL_001d: callvirt instance void [mscorlib]System.IDisposable::Dispose()
25: IL_0022: endfinally
26: } // end handler
27: IL_0023: ret
28: } // end of method Form1::Form1_Load
Dispose() IL
1: .method private hidebysig instance void Form1_Load(object sender,
2: class [mscorlib]System.EventArgs e) cil managed
3: {
4: // Code size 30 (0x1e)
5: .maxstack 1
6: .locals init ([0] class [System.Drawing]System.Drawing.Graphics g)
7: IL_0000: ldarg.0
8: IL_0001: call instance native int [System.Windows.Forms]System.Windows.Forms.Control::get_Handle()
9: IL_0006: call class [System.Drawing]System.Drawing.Graphics [System.Drawing]System.Drawing.Graphics::FromHwnd(native int)
10: IL_000b: stloc.0
11: IL_000c: ldstr "this is between the graphics instantiation and dis"
12: + "posal"
13: IL_0011: call valuetype [System.Windows.Forms]System.Windows.Forms.DialogResult [System.Windows.Forms]System.Windows.Forms.MessageBox::Show(string)
14: IL_0016: pop
15: IL_0017: ldloc.0
16: IL_0018: callvirt instance void [System.Drawing]System.Drawing.Graphics::Dispose()
17: IL_001d: ret
18: } // end of method Form1::Form1_Load
Conclusion
So, as you can see, the "using" method wraps the code inside the scope of the statement within a "try" block of a "try/finally", placing the Dispose() call in the finally, meaning it will always get executed even if an Exception is thrown. However, using the explicit Dispose() method, if an Exception is thrown, then it will not get disposed of, meaning it could be sat on the heap for a few milliseconds or even a few minutes, not good!
I guess this is why MSDN refers to the "using" statement as the "convenient syntax for correct use of IDisposable objects".
I believe the VB developers out there do not have an equivalent available, so make sure you are wrapping all of your disposable objects calls in try/finally blocks!
Update: I have been told that VB.NET 2.0 does actually have a "using" statement as well, which looks surprisingly like the C# syntax! http://msdn.microsoft.com/en-us/library/htd05whh.aspx
Share: digg it! | del.icio.us | furl | Live | Technorati | Facebook
Comments
Post a Comment