RSS 2.0 Feed
RSS 2.0


Atom 1.0 Feed
Atom 1.0

  Why use using? 


qt8gt0bxhw|20009F4EEE83|RyanMain|subtext_Content|Text|0xfbffb20000000000ae00000001000300

The other day I posted again about using Dispose. I guess I just can't post about Dispose without also mentioning using. For those not aware of what using is, I am not talking about the using directive (where you include namespaces in your code such as using System.Text; etc) but the using statement. The using statement defines a scope for an object where the object will be automatically exposed at the end of the scope. The using statement goes hand in hand with calling Dispose since that is what it's purpose is. So if you understand the need to use Dispose with objects that implement the IDisposable interface, then you'll also want to look at using the using statement with those objects.

The syntax for using is very simple. The MSDN docs define the use of using as follows:

using (expression | type identifier = initializer) statement(s)

Basically, the block wraps the type declaration, instanciation and initialization. Then when the block is exited the Dispose method for the object is called. For example, if you're using a StreamReader, you'd wrap it in a using block like so:

using (StreamReader reader = new StreamReader(@"C:\My Files\test.txt"))
{
     string text = reader.ReadToEnd();
}

What benefits do you get by using a using block? Well, it really is a matter of preference. You can do the same thing with or without a using block. For example, with the StreamReader we used earlier, we could also write the same code as follows, without using the using statement:

StreamReader reader = new StreamReader(@"C:\My Files\test.txt");
try
{
    string text = reader.ReadToEnd();
}
finally
{
    reader.Dispose();
}

As a matter of fact, there is no direct mapping between the using statement in C# and the generated MSIL. So the earlier example where we used a using block with the StreamReader can be decompiled to the following MSIL:

  // Code size       31 (0x1f)
  .maxstack  2
  .locals init ([0] class [mscorlib]System.IO.StreamReader reader,[1] string text)
  IL_0000:  ldstr      "C:\\My Files\\test.txt"
  IL_0005:  newobj     instance void [mscorlib]System.IO.StreamReader::.ctor(string)
  IL_000a:  stloc.0
  .try
  {
    IL_000b:  ldloc.0
    IL_000c:  callvirt   instance string [mscorlib]System.IO.TextReader::ReadToEnd()
    IL_0011:  stloc.1
    IL_0012:  leave.s    IL_001e
  }  // end .try
  finally
  {
    IL_0014:  ldloc.0
    IL_0015:  brfalse.s  IL_001d
    IL_0017:  ldloc.0
    IL_0018:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
    IL_001d:  endfinally
  }  // end handler
  IL_001e:  ret

Even without understanding MSIL, you can clearly see what is going on here. The code was essentially translated to a try/finally block calling Dispose in the finally. If I were to take this same IL and convert it back to C# using Reflector then it would be exactly that, a try/finally block where Dispose is called in the finally.

So why use using at all? If all using does is translate to a try/finally block then why would you want to use it? Well, as I said at the beginning, it really does come down to a matter of preference. I think the code is more elegant but others may not and that is OK. However, take any peice of code that does not use using and tell me that Dispose is being called without looking in the finally block. You can't. There's no way you can guarantee that Dispose is being called without looking in the finally block to see. With using, there's nothing to look at. You know it is being called. You know that there's no way you could have forgotten to call Dispose and left some references to unmanaged resources out there somewhere. You know this because it is done automatically for you - and I think that is just cool.

To finish things up, it is important to understand that since the purpose of using is to create a scope for an object where Dispose is automatically called upon leaving the scope that this requires that the object actually implements IDisposable. Using an object that does not implement IDisposable will result in an error, just as manually calling Dispose for the object in a finally block would result in an error. For a list of objects in the framework that implement IDisposable you can look at the IDisposable definition in the docs. However, with that said, you should also implement IDisposable in your own classes that use unmanaged resources such as interop etc.




                   



Leave a comment below.

Comments

  1. Neil 3/18/2004 10:21 AM
    Gravatar
    Great post Ryan.
  2. Tilos Zona 3/18/2004 10:47 AM
    Gravatar
  3. Himadrish 4/13/2005 3:46 AM
    Gravatar
    Is it a good habit to call disposed method? Still if weed to call, then this way we can do so..but in this case we should know it will go through 101% out of 100%. Otherwise, we can not catch the error in our interface.

    Idea is pretty good to used it.

    ~Himadrish
    (himadrish@yahoo.com)
  4. Ihab El Attar 4/29/2005 8:14 AM
    Gravatar
    very good straight forward post
  5. Andy 6/23/2005 12:26 PM
    Gravatar
    What about when you have a component that implements IDisposable and another interface:
    class Foo: System.ComponentModel.Component, IFoobar
    {etc}

    Then you want to instantiate:

    IFoobar fooey = new Foo()
    using(fooey)
    {etc}

    Compiler doesn't like it: Cannot implicitly convert type IFoobar to IDisposable. Can you straighten me out on this?





  6. Calum 7/8/2005 1:49 AM
    Gravatar
    Andy - you're using "fooey" as an IFoobar -- an IFoobar is *not* an IDisposable. If you change the line to:

    Foo fooey = new Foo();

    It should work.
  7. Luke 12/2/2005 7:47 AM
    Gravatar
    I found this while searching on a problem I'm seeing and I sadly see it repeated when I try the try{...} finally{...} code above. I end up getting this error:

    'System.IO.TextReader.Dispose(bool)' is inaccessible due to its protection level

    I can make it work if I do the following, but it seems cludgy.

    static void Main(string[] args)
    {
    StreamReader reader = new StreamReader(@"C:\My Files\test.txt");
    try
    {
    string text = reader.ReadToEnd();
    }
    finally
    {
    IDisposable i = reader;
    i.Dispose();
    }

    }
    }


    Any thoughts?
  8. Ryan Farley 12/2/2005 7:12 PM
    Gravatar
    Luke,

    Really nothing wrong with it. The TextReader class is an abstract base class for the StreamReader and StringReader. And as the message indicated, it's methods, such as it's protected "Dispose" method are not directly accessible.

    Since TextReader implements the IDisposable interface, it is a completely acceptable practice to do just as you did. I usually use syntax such as:

    if (reader is IDisposable) ((IDisposable)reader).Dispose();

    -Ryan
  9. BC 2/13/2007 1:44 PM
    Gravatar
    Using is definitely more elegant however you have to be a bit careful.
    There are some things whose dispose method can throw which causes a problem as you cannot catch anything thrown by dispose and also if any code inside your using block throws an error it will get masked by the error thrown as you exit the using block.
  10. host 6/13/2007 11:29 AM
    Gravatar
    Yes i too think its a bit outdated. I dont use it anymore
  11. küresel ısınmaya hayır 11/23/2007 8:14 AM
    Gravatar
    {
    string text = reader.ReadToEnd();
    }
  12. oyunlar 4/15/2008 6:43 AM
    Gravatar
    Good Code For C#
  13. Christophe 5/11/2008 1:18 PM
    Gravatar
    try/catch/finally and resource protection: mistakes to avoid
  14. Red 1/27/2009 1:30 AM
    Gravatar
    thanks for codes..
    I make an archive for this kind codes in my site..
    http://www.ajanlar.com

    I hope its not a problem for u
  15. Ashish 9/25/2009 11:24 AM
    Gravatar
    Thanks For Explaining the Concept in such an Organized way ,that even a newbie like me is now crystal clear about the Same,Thanks again
Comments have been closed on this topic.



 

News


Also see my CRM Developer blog

Connect:   @ryanfarley@mastodon.social

         

Sponsor

Sections