Click here to Skip to main content
11,433,170 members (56,428 online)
Click here to Skip to main content

The "using" Keyword in C#

, 10 Jan 2007 CPOL
Rate this:
Please Sign up or sign in to vote.
A look at the C# "using" keyword. What happens behind the scenes.

Introduction

I was at work today, and someone asked me what happens when you use the using keyword in C#. Most people will tell you that it is something you use that will clean up any unmanaged resources for the specified object, which is not incorrect. But what actually happens at the IL level? How does it "clean up" unmanaged resources? I had my assumptions, but I really didn't know. So, I set out to find out for myself.

Tests

I decided I was going to run through a couple of tests:

Test #1

I wanted to see what the generated MSIL code looks like when I use the using keyword. So, I wrote some very simple sample code in C#, compiled it, then I decompiled it using ildasm to see the MSIL code.

Test #2

I wanted to see if I could write code without using the using keyword that would generate the exact same MSIL code. This process was a little more trial and error, but was fairly easy.

Test #1

Here is my sample code:

[STAThread]
private static void Main(string[] args)
{
      using (Bitmap bitmap1 = new Bitmap(100, 100))
      {
            Console.WriteLine("Width: {0}, Height: {1}", bitmap1.Width, bitmap1.Height);
      }
      Console.ReadLine();
}

As you can see... nothing special in the code. Create a new Bitmap inside a using statement, write some output to the console, wait for user input, then exit.

What does this look like when we build the app, then decompile it into MSIL? Check it out:

.method private hidebysig static void Main(string[] args) cil managed
{
      .custom instance void [mscorlib]System.STAThreadAttribute::.ctor()
      .entrypoint
      .maxstack 4
      .locals init (
            [0] [System.Drawing]System.Drawing.Bitmap bitmap1)
      L_0000: ldc.i4.s 100
      L_0002: ldc.i4.s 100
      L_0004: newobj instance void 
	[System.Drawing]System.Drawing.Bitmap::.ctor(int32, int32)
      L_0009: stloc.0 
      L_000a: ldstr "Width: {0}, Height: {1}"
      L_000f: ldloc.0 
      L_0010: callvirt instance int32 [System.Drawing]System.Drawing.Image::get_Width()
      L_0015: box int32
      L_001a: ldloc.0 
      L_001b: callvirt instance int32 [System.Drawing]System.Drawing.Image::get_Height()
      L_0020: box int32
      L_0025: call void [mscorlib]System.Console::WriteLine(string, object, object)
      L_002a: leave.s L_0036
      L_002c: ldloc.0 
      L_002d: brfalse.s L_0035
      L_002f: ldloc.0 
      L_0030: callvirt instance void [mscorlib]System.IDisposable::Dispose()
      L_0035: endfinally 
      L_0036: call string [mscorlib]System.Console::ReadLine()
      L_003b: pop 
      L_003c: ret 
      .try L_000a to L_002c finally handler L_002c to L_0036
}

Test #1 Results

So the results from test #1 are interesting. The using keyword is basically a try - finally block, without a catch , where IDisposable.Dispose() is called in the finally . One interesting thing to note is that the Bitmap constructor is called before the try block begins. This tells me that if, in the Bitmap constructor, an unmanaged resource is allocated, but not freed, then the constructor throws an exception, the unmanaged resource will not get freed by a call to the IDisposable.Dispose(). This also assumes that the IDisposable is implemented properly. Therefore the using keyword is useless if the IDisposable is not implemented properly. The constructor should clean up resources if it fails, and the Dispose() method should clean up all unmanaged resources. Chances are good that Microsoft has implemented IDisposable correctly in their classes, so watch out for this if you are implementing your own IDisposable.

Test #2

Based on the MSIL code that resulted from Test #1, I decided to write the same code using try - finally blocks. This is what I came up with:

[STAThread]
private static void Main(string[] args)
{
      Bitmap bitmap1 = new Bitmap(100, 100);
      try
      {
            Console.WriteLine("Width: {0}, Height: {1}", bitmap1.Width, bitmap1.Height);
      }
      finally
      {
            if (bitmap1 != null)
            {
                  bitmap1.Dispose();
            }
      }
      Console.ReadLine();
}

And this is what it looked like in MSIL:

.method private hidebysig static void Main(string[] args) cil managed
{
      .custom instance void [mscorlib]System.STAThreadAttribute::.ctor()
      .entrypoint
      .maxstack 4
      .locals init (
            [0] [System.Drawing]System.Drawing.Bitmap bitmap1)
      L_0000: ldc.i4.s 100
      L_0002: ldc.i4.s 100
      L_0004: newobj instance void 
	[System.Drawing]System.Drawing.Bitmap::.ctor(int32, int32)
      L_0009: stloc.0 
      L_000a: ldstr "Width: {0}, Height: {1}"
      L_000f: ldloc.0 
      L_0010: callvirt instance int32 [System.Drawing]System.Drawing.Image::get_Width()
      L_0015: box int32
      L_001a: ldloc.0 
      L_001b: callvirt instance int32 [System.Drawing]System.Drawing.Image::get_Height()
      L_0020: box int32
      L_0025: call void [mscorlib]System.Console::WriteLine(string, object, object)
      L_002a: leave.s L_0036
      L_002c: ldloc.0 
      L_002d: brfalse.s L_0035
      L_002f: ldloc.0 
      L_0030: callvirt instance void [System.Drawing]System.Drawing.Image::Dispose()
      L_0035: endfinally 
      L_0036: call string [mscorlib]System.Console::ReadLine()
      L_003b: pop 
      L_003c: ret 
      .try L_000a to L_002c finally handler L_002c to L_0036
}

Test #2 Results

It is almost exactly like the MSIL generated from the using keyword, except this calls Image.Dispose() rather than IDisposable.Dispose(), but the effect is the same. Just for fun, I regenerated C# code using Lutz Roeder's .NET Reflector, which is an invaluable tool, and here is the result:

[STAThread]
private static void Main(string[] args)
{
      using (Bitmap bitmap1 = new Bitmap(100, 100))
      {
            Console.WriteLine("Width: {0}, Height: {1}", bitmap1.Width, bitmap1.Height);
      }
      Console.ReadLine();
}

This looks exactly like our original code!!!

Conclusion

This was really a fun experiment that revealed a lot about the way .NET works behind the scenes. I hope you guys enjoy this as much as I did.

History

  • 10th January, 2007: Initial post

License

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

Share

About the Author

pfemiani
Architect People Media
United States United States
My name is Peter Femiani and I am a graduate of Arizona State University with a B.S. in Economics. I have been writing code since I was about 14.

Comments and Discussions

 
GeneralMy vote of 5 Pin
Santosh K. Tripathi13-Mar-15 1:18
professionalSantosh K. Tripathi13-Mar-15 1:18 
Question5! Pin
Sharath C V19-Jun-13 20:34
memberSharath C V19-Jun-13 20:34 
GeneralMy vote of 5 Pin
Sharath C V19-Jun-13 20:31
memberSharath C V19-Jun-13 20:31 
QuestionAbout Using keyword.. Pin
gopesh201010-Sep-12 19:59
membergopesh201010-Sep-12 19:59 
GeneralMy vote of 5 Pin
Farhan Ghumra31-Jul-12 1:01
memberFarhan Ghumra31-Jul-12 1:01 
GeneralMy vote of 5 Pin
sytuan18-Jun-12 21:30
membersytuan18-Jun-12 21:30 
GeneralMy vote of 5 Pin
drake2k1-Jun-12 9:57
memberdrake2k1-Jun-12 9:57 
GeneralMy vote of 5 Pin
arunk52521-Dec-11 13:49
memberarunk52521-Dec-11 13:49 
GeneralMy vote of 4 Pin
kernelvirii17-Nov-11 6:27
memberkernelvirii17-Nov-11 6:27 
GeneralImage.Dispose() not the same as IDisposable.Dispose() Pin
Lady-green11-May-07 22:10
memberLady-green11-May-07 22:10 
Generala correct constuctor behaviour Pin
zhgmytz24-Jan-07 1:11
memberzhgmytz24-Jan-07 1:11 
GeneralSome supplement Pin
crucify17-Jan-07 15:42
membercrucify17-Jan-07 15:42 
QuestionDefinitive IDisposable reference? Pin
Doug K. Wilson11-Jan-07 9:19
memberDoug K. Wilson11-Jan-07 9:19 
AnswerRe: Definitive IDisposable reference? Pin
ADLER111-Jan-07 11:49
memberADLER111-Jan-07 11:49 
GeneralRe: Definitive IDisposable reference? Pin
Scott Dorman11-Jan-07 14:53
memberScott Dorman11-Jan-07 14:53 
AnswerRe: Definitive IDisposable reference? Pin
Scott Dorman11-Jan-07 14:54
memberScott Dorman11-Jan-07 14:54 
GeneralRe: Definitive IDisposable reference? Pin
Doug K. Wilson11-Jan-07 15:34
memberDoug K. Wilson11-Jan-07 15:34 
GeneralRe: Definitive IDisposable reference? Pin
Scott Dorman12-Jan-07 14:06
memberScott Dorman12-Jan-07 14:06 
AnswerRe: Definitive IDisposable reference? Pin
Brent Finney12-Jan-07 6:52
memberBrent Finney12-Jan-07 6:52 
GeneralRe: Definitive IDisposable reference? Pin
Scott Dorman12-Jan-07 14:11
memberScott Dorman12-Jan-07 14:11 
GeneralUh.. Pin
Filip Duyck11-Jan-07 6:18
memberFilip Duyck11-Jan-07 6:18 
General[Message Deleted] Pin
TJoe11-Jan-07 17:06
memberTJoe11-Jan-07 17:06 
GeneralRe: Uh.. Pin
Jamie Nordmeyer12-Jan-07 8:41
memberJamie Nordmeyer12-Jan-07 8:41 
GeneralRe: Uh.. Pin
Scott Dorman12-Jan-07 14:20
memberScott Dorman12-Jan-07 14:20 
GeneralRe: Uh.. Pin
Jamie Nordmeyer12-Jan-07 14:24
memberJamie Nordmeyer12-Jan-07 14:24 
GeneralRe: Uh.. Pin
Scott Dorman12-Jan-07 14:31
memberScott Dorman12-Jan-07 14:31 
GeneralRe: Uh.. Pin
Jamie Nordmeyer12-Jan-07 14:45
memberJamie Nordmeyer12-Jan-07 14:45 
GeneralRe: Uh.. Pin
Scott Dorman12-Jan-07 15:01
memberScott Dorman12-Jan-07 15:01 
GeneralRe: I didn't know that ?? operator Pin
Jcmorin15-Jan-07 11:49
memberJcmorin15-Jan-07 11:49 
GeneralRe: I didn't know that ?? operator Pin
LunatiCord15-Jan-07 22:23
memberLunatiCord15-Jan-07 22:23 
AnswerRe: Uh.. Pin
Horia Tudosie17-Jan-07 5:22
memberHoria Tudosie17-Jan-07 5:22 
GeneralRe: Uh.. Pin
Scott Dorman12-Jan-07 14:24
memberScott Dorman12-Jan-07 14:24 
GeneralRe: Uh.. Pin
Filip Duyck13-Jan-07 10:15
memberFilip Duyck13-Jan-07 10:15 
GeneralRe: Uh.. Pin
Scott Dorman13-Jan-07 13:43
memberScott Dorman13-Jan-07 13:43 
GeneralRe: Uh.. Pin
Filip Duyck15-Jan-07 6:56
memberFilip Duyck15-Jan-07 6:56 
GeneralRe: Uh.. [modified] Pin
Scott Dorman15-Jan-07 7:03
memberScott Dorman15-Jan-07 7:03 
Try to compile the code sample you provided:

bool returnValue = false;
Stream s = null;
try
{
   s = new FileStream("file"));
 
   // do some work
}
catch { throw; }
finally 
{ 
   if (s != null) s.Dispose();
   return returnValue; 
}
It won't compile and will give the compile error I mentioned.

However, if you put this in a using block:
bool returnValue = false;
using (Stream s = new FileStream("file"))
{
   s = new FileStream("file"));
 
   // do some work
   return returnValue;
}
It will compile because the compiler is actually translating this to something along the following lines:
bool returnValue = false;
Stream s = null;
try
{
   s = new FileStream("file"));
 
   // do some work
}
catch { throw; }
finally 
{ 
   if (s != null) s.Dispose();
}
return returnValue;
The key difference here is the placement of the return statement. The IL between the last try...finally and the using will be very similar. The difference is in the syntax the user sees.

-----------------------------
In just two days, tomorrow will be yesterday.


-- modified at 12:15 Monday 15th January, 2007
GeneralRe: Uh.. Pin
Filip Duyck15-Jan-07 8:03
memberFilip Duyck15-Jan-07 8:03 
GeneralRe: Uh.. Pin
Scott Dorman15-Jan-07 8:22
memberScott Dorman15-Jan-07 8:22 
GeneralRe: Uh.. Pin
Brian Leach15-Jan-07 12:58
memberBrian Leach15-Jan-07 12:58 
GeneralRe: Uh.. Pin
Scott Dorman15-Jan-07 18:32
memberScott Dorman15-Jan-07 18:32 
GeneralRe: Uh.. Pin
Filip Duyck16-Jan-07 23:15
memberFilip Duyck16-Jan-07 23:15 
GeneralRe: Uh.. Pin
MaxGuernsey16-Jan-07 20:25
memberMaxGuernsey16-Jan-07 20:25 
GeneralRe: Uh.. Pin
Filip Duyck16-Jan-07 23:13
memberFilip Duyck16-Jan-07 23:13 
GeneralRe: Uh.. Pin
MaxGuernsey17-Jan-07 7:39
memberMaxGuernsey17-Jan-07 7:39 
GeneralRe: Uh.. Pin
Filip Duyck17-Jan-07 8:26
memberFilip Duyck17-Jan-07 8:26 
GeneralRe: Uh.. Pin
MaxGuernsey17-Jan-07 15:17
memberMaxGuernsey17-Jan-07 15:17 
GeneralRe: Uh.. Pin
Filip Duyck17-Jan-07 23:28
memberFilip Duyck17-Jan-07 23:28 
GeneralRe: Uh.. Pin
rlivelyppk17-Jan-07 12:35
memberrlivelyppk17-Jan-07 12:35 
GeneralRe: Uh.. Pin
Filip Duyck17-Jan-07 12:42
memberFilip Duyck17-Jan-07 12:42 
GeneralRe: Uh.. Pin
amit.andharia@etatvasoft.com16-Jan-09 23:40
memberamit.andharia@etatvasoft.com16-Jan-09 23:40 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.150428.2 | Last Updated 10 Jan 2007
Article Copyright 2007 by pfemiani
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid