tags:

views:

1016

answers:

6

Given this code:

using (var conn = new SqlConnection("..."))
{
    conn.Open();
    using (var cmd = conn.CreateCommand())
    {
        cmd.CommandText = "...";
        using (var reader = cmd.ExecuteReader())
        {
            while (reader.Read())
            {
                // ...
            }
        }
    }
}

I'm used to writing try/catch/finally blocks for my data access, however, I'm being exposed to "using" which seems like a much simpler method of doing this. However, I'm trying to figure out how to catch exceptions that may occur.

Could you please give me an example of how you'd catch exceptions?

Edited to add:

I'm being lead to believe that "using" is a replacement for my try/catch/finally blocks. I understand that using doesn't catch exceptions. So how is this a replacement?

+5  A: 

Using statements have nothing to do with Exceptions. Using blocks just insure that Dispose is called on the object in the using block, when it exits that block. I.E:

using(SqlConnection conn = new SqlConnection(conStr))
{
   //use conn
}//Dispose is called here on conn.

If opening the connection raises an exception (or anything else in that block for that matter) it will still bubble to the top and will be like any other unhanded exception.

BFree
+17  A: 

using isn't designed to catch exceptions; it's designed to give you an easy way to wrap a try/finally around an object that needs to be disposed. If you need to catch and handle exceptions then you'll need to expand it into a full try/catch/finally or put a containing try/catch around the whole thing.


To answer your edit (is using a replacement for try/catch/finally?) then no, it isn't. Most of the time when using a disposable resource you aren't going to handle the exception there and then because there's normally nothing useful you can do. So it provides a convenient way to just ensure that the resource is cleaned up irrespective of what you're trying to do works or not.

Typically code that deals with disposable resources is working at too low a level to decide what the correct action is on failure, so the exception is left to propagate to the caller who can decide what action to take (e.g. retry, fail, log, etc.). The only place where you'd tend to use a catch block with a disposable resource is if you're going to translate the exception (which is, I assume, what your data access layer is doing).

Greg Beech
+7  A: 

If you want to catch exceptions there you probably should go back to using try/catch/finally. Just put the .Dispose() calls in the finally block.

Kevin Tighe
He can wrap the using into a try/catch-block. If an error is caught, Dispose will be called (if it exists) before entering the catch.
Leonidas
That's true, but then you've got one more level of indentation and the using statement is not that convenient anymore. I'd prefer to just have the one try/catch/finally handle everything (but that's a minor style thing).
Kevin Tighe
+3  A: 

Wrap all the using statements into a try/catch. Like everyone else has said, using is for cleaning up classes that implement the IDisposable interface

try
{

 using (var conn = new SqlConnection("..."))
 {
    conn.Open();
    using (var cmd = conn.CreateCommand())
    {
        cmd.CommandText = "...";
        using (var reader = cmd.ExecuteReader())
        {
            while (reader.Read())
            {
                // ...
            }
        }
    }
 }
}
catch(Exception ex)
{
//Handle, log, rethrow exception
}
Chuck Conway
How is this better that try/catch/finally and calling dispose in my finally block?
GregD
Erik, why would you call dispose in the finally block? When you can use the using statements? If you use the finally block then you have to declare the objects outside the try block...
Chuck Conway
Internally that's the same IL the using statement will generate Charles. It's really just syntactical candy.
Chris Marisic
But it's less code I have to worry about :-)
Chuck Conway
+1  A: 

You can still catch (or ignore) exceptions exactly as you would have previously. The point is that you no longer need to worry about disposing of the database connection.

ie, If your application requires that you trap exceptions for some other reason (eg, logging) then go ahead, but you no longer need to do so if you only want to dispose of the database connection:

using (SqlConnection conn = new SqlConnection(...))
{
    // do your db work here
    // whatever happens the connection will be safely disposed
}

If you want to catch the exception for some other reason, you can still do so:

try
{
    using (SqlConnection conn = new SqlConnection(...))
    {
        // do your db work here
        // whatever happens the connection will be safely disposed
    }
}
catch (Exception ex)
{
    // do your stuff here (eg, logging)
    // nb: the connection will already have been disposed at this point
}
finally
{
    // if you need it
}
LukeH
That's funny. I was wondering if you were going to pop your head in over here :)
GregD
+3  A: 
using (var cmd = new SqlCommand("SELECT * FROM Customers"))
{
    cmd.CommandTimeout = 60000;
    ...
}

is syntactic sugar for

var cmd = new SqlCommand("SELECT * FROM Customers");
try
{
    cmd.CommandTimeout = 60000;
    ...
}
finally
{
    if (cmd != null)
        cmd.Dispose();
}

So when people are telling you that "using" is a replacement for try/catch/finally they are implying that you should use the long-hand form but add in your catch block:

var cmd = new SqlCommand("SELECT * FROM Customers");
try
{
    cmd.CommandTimeout = 60000;
    ...
}
catch (Exception ex)
{
    ...//your stuff here
}
finally
{
    if (cmd != null)
        cmd.Dispose();
}
RogueBadger
If cmd is created in the try block, you can't call dispose on it in the finally block.
Lucas McCoy
@Lucas Aardvark - of course, Thanks! Fixed.
RogueBadger