C# - Try/Catch/Finally and Using proper order

Viewed 636

I know this question has been asked quite a few times but i still don't understand what the proper order should be.

If you want to catch an exception in the objects creation you have to put the try and catch outside of the using statement:

try { using... } catch (Exception e) { }

And if you want to catch an exception after the objects creation then:

using(...) { try {...} catch (Exception e) {} }

But what if you want to catch both during and after the objects creation? Would it be:

try { using(...) { try {...} catch (Exception e) {} } } catch (Exception e) { }

Or would it be better to just use a try, catch, and a finally with a dispose?

4 Answers

The using block is more about the Disposal than the creation. As mentioned in the documentation, it's a shortcut to this code:

{
    Font font1 = new Font("Arial", 10.0f);
    try
    {
        byte charset = font1.GdiCharSet;
    }
    finally
    {
        if (font1 != null)
            ((IDisposable)font1).Dispose();
    }
}

This is the definition of a try-catch block

The try block contains the guarded code that may cause the exception. The block is executed until an exception is thrown or it is completed successfully.

So from there, the strategy is up to you. This piece of code:

try
{
    using(Font font1 = new Font("Arial", 10.0f))
    {
        byte charset = font1.GdiCharSet;
    }
}

will be translated as:

try
{
    Font font1 = new Font("Arial", 10.0f);
    try
    {
        byte charset = font1.GdiCharSet;
    }
    finally
    {
        if (font1 != null)
            ((IDisposable)font1).Dispose();
   }
}

As you can see, you are catching exceptions cause by the constructor, the block and also the Dispose.

Whereas this:

using(Font font1 = new Font("Arial", 10.0f))
{
    try
    {
        byte charset = font1.GdiCharSet;
    }
}

will be translated as:

Font font1 = new Font("Arial", 10.0f);
try
{
    try //This is your try
    {
      byte charset = font1.GdiCharSet;
    }
}
finally
{
    if (font1 != null)
        ((IDisposable)font1).Dispose();
}

So here you will catch exception cause neither by the constructor nor the Dispose.

Any exception thrown within the context of your try block will be handled by the corresponding catch block. You can have, in this instance, one try block that can catch exceptions from multiple sources and handle them as you wish. Consider the following code...

try
{
    using(var con = DataService.GetSomethingDisposable()) // Possible InvalidOperationException();
    {
        // Do what you need here
        // Possible Exception here
    }
}
catch(InvalidOperationException ex)
{
    // Handle as you will
}
catch(Exception ex) // Catch any other exception
{
    // Handle as you will
}

So with this you can catch and respond to any exception that arises with the same try...catch block.

MSDN Reference https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement

When the lifetime of an IDisposable object is limited to a single method, you should declare and instantiate it in the using statement. The using statement calls the Dispose method on the object in the correct way, and (when you use it as shown earlier) it also causes the object itself to go out of scope as soon as Dispose is called. Within the using block, the object is read-only and cannot be modified or reassigned.

Option 1 would catch both scenarios:

try { using() } catch (Exception) {}

If you create a new object which throws an exception on initialisation, the exception will be caught in your catch block. Equally, if something inside your using block throws an exception, that will also be caught in the catch block.

An exception will always bubble up to the first catch block which is capturing that type of exception. If there's nothing to catch the exception, it'll likely bubble all the way up and terminate your application

Related