views:

328

answers:

11

I'm somewhat new to c#, more accustomed to scripting languages. I like the idea of 'using', you instantiate an object, and then you operate within its scope as long as you need it, then you let it dispose of itself when it's done its purpose.

But, it's not natural for me. When people show me examples using it, I recognize it as a good tool for the job, but it never occurs to me to solve problems with it in my own programming.

How can I recognize good places to use using and how do I use it in conjunction with try-catch blocks. Do they go inside the block, or do you usually want to enclose a using statement within a try block?

+17  A: 

using can only be used with types that implement IDisposable; it guarantees that the Dispose() method will be called even if an error occurs.

This code:

using (MyDisposableType x = new MyDisposableType())
{  
    // use x
}

is equivalent to this:

MyDisposableType x = new MyDisposableType();
try
{  
    // use x
}
finally 
{ 
    x.Dispose(); 
}
Mitch Wheat
So... use it on any object that implements IDisposable? Always?
danieltalsky
And what about exception handling?
danieltalsky
would downvoters please leave a comment. Thanks.
Mitch Wheat
Note that you should never put transaction logic in finally as it is not absolutely guaranteed to run. Until we get transactional memory at least. E.g. If you pull out the power plug finally won't run!
Jonathan Parker
how would you do it then? Prevent the code from doing something at a power down :D
PoweRoy
It would be a shame to leak resources by not disposing them on a power down :)
dr. evil
Weird, I was told that finally is _always_ guaranteed to run, whether there is an exception or not. Haven't thought about the power going down, though... ;P
Pawel Krakowiak
@Jonathan Parker - there is no better place to put transactional logic than in 'finally'.
Daniel Earwicker
+8  A: 

I rarely write try/catch blocks - most exceptions get thrown up to (near) the top of the stack. If I do need a try/catch block, I'm not sure I'm particularly consistent between putting it inside the using statement vs outside. It really depends on whether you want the resource to be disposed before of after your exception handling code is run.

If you're asking about when you should be writing using statements - any time you "own" an object which implements IDisposable (either directly or indirectly through inheritance) and control its lifetime. That's usually an object which uses an unmanaged resource like a file handle or network connection. It's not always hugely obvious, but you learn through experience. Almost anything to do with IO will be disposable, and Windows handles (for fonts etc) are similar.

Jon Skeet
To clarify objects that implement IDisposable directly or through inheritance (as danieltalsky is "somewhat new to C#").
Jonathan Parker
Thanks Jonathan - edited appropriately.
Jon Skeet
Well, by "somewhat new to C#" I mean, "have been writing commercial code in C# for less than 8 months". I was, for instance, already familiar with the connection of "using" to "IDisposable" which I do mention in the question. It was the "lifetime control" part I was missing.
danieltalsky
+1  A: 

WHat Mitch said, plus..

You can use the using statement outside or inside a try..catch block it really would depend on what you are trying to achieve i.e. whether you reasonably expect something to throw an exception whilst using a particular object which you plan to recover from, for example.

By the same token, you could also Dispose of an object which implements IDisposable in a finally block if you needed to.

RobS
+2  A: 

I use to think of it as "Use it every time when type implements IDisposable and you you're not goinng to need this particular instance any more".

Dmitry Ornatsky
+1  A: 

Use using when you need deterministic object disposal. For example, if you open a file, the file is locked. You will often want the file to be closed as soon as possible so that other programs could access it. If you don't use using and write smth like:

System.IO.FileStream writeStream = new System.IO.FileStream( fileName, System.IO.FileMode.OpenOrCreate ) );
System.IO.BinaryWriter writer = new System.IO.BinaryWriter( writeStream ) );
//do smth

and an exception occurs during "do smth" you don't know when the objects operating on a file are actually disposed and file is closed. With using you know for sure that once you've left the using statement block - either directly or via exception the object in the useing statement is disposed by calling IDisposable::Dispose:

using( System.IO.FileStream writeStream = new System.IO.FileStream( fileName, System.IO.FileMode.OpenOrCreate ) ) {
    using( System.IO.BinaryWriter writer = new System.IO.BinaryWriter( writeStream ) ) {
        //do stmth
    }
}
sharptooth
No, the object *isn't* finalized. It's only disposed. Finalization and disposal are very different. Usually disposal will suppress a finalizer (if there is one) but they're not the same thing.
Jon Skeet
"Use using when you need deterministic object disposal." It seem to me that if an object implements IDisposable you should always dispose it if the object is not needed any more. By implementing IDisposable the object says "I (might) use resources that needs to be disposed".
Petar Repac
What if implementation of the object in question changes and disposing at once becomes critical ? What is the benefit of non disposing right after usage ?
Petar Repac
You get cleaner code without using-statements.
sharptooth
+1  A: 

You can enclose a using inside a try/catch block and you can enclose a try/catch block inside a using.

One situation where using is nice is when you are doing database operations using DBConnection and DBCommands:

using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand(sql, conn))
{
  // do something here
}

Now when you leave the using blocks your command is disposed and the connection is closed.

Rune Grimstad
+1  A: 

What Mitch said is right. So the main use of using is to ensure that IDisposable objects get disposed of, without having to code a try/catch or try/finally statement.

Now, there's a more advanced use you might find interesting as well. When you use a using statement, the compiler generates a try/finally, and it also generates a call to Dispose() for you inside of the finally that it generates. You can use this Dispose() method as a "hook" to do anything you want ... doesn't have to be related to releasing resources.

For example, Jeffrey Richter uses this in a timer object he wrote. You can do something like this with it (conceptual only):

using(var x = new Timer())
{
  // Do the operation you want timed
}

// Now, the timer has been stopped, because the 
// compiler-generated call to Dispose() has already 
// occurred, and Jeffrey uses Dispose() to stop 
// the timer.
Charlie Flowers
Seems little bit tricky. After the closing brace you don't have access to x. How can you then take advantage of the stopped timer ?
Petar Repac
Yes, that's true. In the case of Richter's timer, he outputs the elapsed time (and the number of garbage collections that have occurred) to the Console. So he had no other need to reference the object after the closing brace.
Charlie Flowers
However, there are ways to achieve that too if you want. The object could be told to fire an event or place results into a collection. Or you could parameterize the object with a lambda action to perform inside itself. But this is getting too far away from the original question.
Charlie Flowers
+2  A: 

If you want to know how to creatively use it within your own designs, look through some of your own code for situations where a particular bit of code absolutely must execute before the enclosing block is exited. These are the situations where try/finally or using can help you.

In particular, if you've tried to achieve this by catching all exceptions, then you really must change to try/finally or using instead.

If the pattern occurs several times, you could create a class that implements IDisposable in order to capture the pattern, and allowing you to invoke the pattern with the using statement. But if you have a specific case that appears to be a one-off, then just use try/finally.

The two are very similar, really - using is specified in terms of try/finally, but even if we only had using, we could build try/finally ourselves:

public class DisposeAnything : IDisposable
{
    public Action Disposer;

    public void Dispose()
    {
        Disposer();
    }
}

Now you could say:

using (new DisposeAnything 
      {
          Disposer = () => File.Delete(tempFileName) 
      })
{
    // blah
}

Which is the same as:

try
{
    // blah
}
finally
{
    File.Delete(tempFileName);
}

Just think of it as a way to get some code to execute upon leaving a scope.

Daniel Earwicker
Hey, parameterizing the dispose logic is an interesting idea. I imagine there are many ways to do that. Cool.
Charlie Flowers
Taken to the above extreme, there's not a lot of point to it! But yes there are probably many half-way cases. You may find this discussion interesting: http://incrediblejourneysintotheknown.blogspot.com/2009/02/functional-replacement-for-using.html
Daniel Earwicker
+1  A: 

If a class implements IDisposable, it's probably for good reason. So any class that implements IDisposable should be disposed.

Dave Van den Eynde
+1  A: 

Given that it is what is known as "syntactic sugar" and will produce the same IL as a try/finally dispose construct, it is really just a nice way of "short-handing" such code.

I like to use it to simplify sections of code where disposable objects are used a lot i.e. access to resources such as files and graphics objects and I want to make sure that I don't forget to handle the disposing of the resource object.

Gordon Mackie JoanMiro
A: 

I've noticed that when the Dispose method is known to do notice, so programmers don't bother calling it as it seems pointless. However, if the object implements IDisposable it's (hopefully) for a reason and future versions of that object may actually have code in the Dispose method - so always call it.

dommer