Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are these try/catch'es equivalent?

Scenario

I have a method that does database operation (let's say). If during that operation any exception is raised, I just want to throw that exception to the caller. I don't want to do any specific task in the catch block, assuming caller will do whatever it wants to do with that exception. In this scenario, which one is appropriate exception handling technique?

try
{
    // Some work that may generate exception
}
catch(Exception)
{
    throw;
}
finally
{
    // Some final work
}

Is the above equivalent to the following try/catch/finally?

try
{
    // Some work that may generate exception
}
catch
{
    throw;
}
finally
{
    // Some final work
}

Is the above equivalent to the following try/finally?

try
{
    // Some work that may generate exception
}
finally
{
    // Some final work
}

Which one is better than the other? Which one should be used?

like image 940
Bhuban Shrestha Avatar asked Jan 26 '17 12:01

Bhuban Shrestha


People also ask

Does VBA have try catch?

The Try-Catch method prevents program crashes when an internal error occurs in computer programming. It is useful to prevent system errors and let the smooth flow of code execution occur. However, unlike other programming languages, VBA does not have the Try-Catch block.

Is try catch the same as if else?

In 'try-catch' the codes to handle the exceptions and what exception to be handled, that are easily readable. In 'if-else', we have one else block corresponding to one if block. Or we need to define another condition with command 'else if'. In 'try-catch' we don't have to define each 'try' block with a 'catch' block.

What is E in try catch?

'e' is just a variable. ('e' stands for exception, but you can rename it anything you like, however, the data type has to remain 'Exception') The 'e' variable stores an exception-type object in this case.

Which is better try catch or throws?

From what I've read myself, the throws should be used when the caller has broken their end of the contract (passed object) and the try-catch should be used when an exception takes place during an operation that is being carried out inside the method.


2 Answers

No, they are not equivalent. They may be equivalent in some cases, but the general answer is no.

Different kinds of catch blocks

catch block with a specified exception type

The following will only catch managed exceptions that inherit from System.Exception and then executes the finally block, which will happen regardless of whether an exception was thrown or not.

try
{
   // Some work that may generate exception
}
catch (Exception)
{
   throw;
}
finally
{
   // Some final work
}

catch block without a specified exception type

The following catch block without a type specifier will also catch non-managed exceptions that are not necessarily represented by a managed System.Exception object, and then executes the finally block, which will happen regardless of whether an exception was thrown or not.

try
{
   // Some work that may generate exception
}
catch
{
   throw;
}
finally
{
   // Some final work
}

finally block without a catch block

If you do not have a catch block at all, your finally will still be executed regardless of whether or not an exception occoured.

try
{
   // Some work that may generate exception
}
finally
{
  // Some final work
}

When are they equivalent?

In case your catch block doesn't specify an exception and only contains the throw; statement, the last two are indeed equivalent. In case you don't care about non-managed exceptions and your catch block only contains the throw; statement, all three can be considered equivalent.

Notes

A note about throw

The following two pieces of code contain a subtle difference. The latter will re-throw the exception, meaning that it will rewrite the exception's stack trace, so these are definitely not equivalent:

catch (Exception e)
{
    throw;
}

And

catch (Exception e)
{
    throw e;
}

In case you use finally with an IDisposable, the following two pieces of code are almost equivalent, but with some subtle differences:

  • When the object is null, the using statement won't give you a NullReferenceException
  • When using the try-finally technique, the variable remains in scope, although it is very discouraged to use any object after it has been disposed. However you can still reassign the variable to something else.

    Something obj = null; try { obj = new Something() // Do something } finally { obj.Dispose(); }

And

using (var obj = new Something())
{
    // Do something
}
like image 148
Venemo Avatar answered Sep 18 '22 15:09

Venemo


You have some good answers so far, but there is an interesting difference that they did not mention so far. Consider:

try { ImpersonateAdmin(); DoWork(); } 
finally { RevertImpersonation(); }

vs

try { ImpersonateAdmin(); DoWork(); }
catch { RevertImpersonation(); throw; }
finally { RevertImpersonation(); }

Suppose DoWork throws.

Now the first question at hand is "is there a catch block that can handle this exception", because if the answer is "no" then the behaviour of the program is implementation-defined. The runtime might choose to terminate the process immediately, it might choose to run the finally blocks before it terminates the process, it might choose to start a debugger broken at the point of the unhandled exception, it might choose to do anything it likes. Programs with unhandled exceptions are permitted to do anything.

So the runtime starts looking for a catch block. There's none in this try statement, so it looks up the call stack. Suppose it finds one with an exception filter. It needs to know if the filter will permit the exception to be handled, so the filter runs before impersonation is reverted. If the filter accidentally or deliberately does something that only an admin can do, it will succeed! This might not be what you want.

In the second example, the catch catches the exception immediately, reverts the impersonation, throws, and now the runtime starts looking for a catch block to handle the re-throw. Now if there is a filter it runs after the impersonation is reverted. (And of course the finally then reverts again; I assume that reverting impersonation is idempotent here.)

This is an important difference between these two code snippets. If it is absolutely positively forbidden for any code to see the global state that was messed up by the try and cleaned up by the finally, then you have to catch before finally. "Finally" does not mean "immediately", it means "eventually".

like image 21
Eric Lippert Avatar answered Sep 18 '22 15:09

Eric Lippert