what is the difference between
try { }
catch
{ throw; }
and
try { }
catch(Exception e)
{ throw e;}
and when should i use one or another?
what is the difference between
try { }
catch
{ throw; }
and
try { }
catch(Exception e)
{ throw e;}
and when should i use one or another?
The first preserves the stack trace while the second resets it. This means that if you use the second approach the stack trace of the exception will always start from this method and you will lose the original exception trace which could be disastrous for someone reading exception logs as he will never find out the original cause of the exception.
The second approach might be useful when you want to add additional information to the stack trace but it is used like this:
try
{
// do something
}
catch (Exception ex)
{
throw new Exception("Additional information...", ex);
}
There's a blog post discussing the differences.
You should use
try { }
catch(Exception e)
{ throw }
if you want to do something with the exception before re-throwing it (logging for example). The lonely throw preserves stack trace.
You would normally use 1 of these patterns:
try { ... }
catch (Exception ex) // the (Exception ex) part is optional
{
// clean up something, maybe Log(ex)
throw; // re-throw, preserving stack-trace (inc point of origin)
}
or
try { ... }
catch(Exception ex)
{
Exception newContext = new MyException("...", ex); // ex becomes the inner exception
throw newContext; // starts new stk-trace but the old one is saved in ex
}
The constructions
try { ... }
catch () { ... } /* You can even omit the () here */
try { ... }
catch (Exception e) { ... }
are similar in that both will catch every exception thrown inside the try
block (and, unless you are simply using this to log the exceptions, should be avoided). Now look at these:
try { ... }
catch ()
{
/* ... */
throw;
}
try { ... }
catch (Exception e)
{
/* ... */
throw;
}
try { ... }
catch (Exception e)
{
/* ... */
throw e;
}
The first and second try-catch blocks are EXACTLY the same thing, they simply rethrow the current exception, and that exception will keep its "source" and the stack trace.
The third try-catch block is different. When it throws the exception, it will change the source and the stack trace, so that it will appear that the exception has been thrown from this method, from that very line throw e
on the method containing that try-catch block.
Which one should you use? It really depends on each case.
Let's say you have a Person
class with a .Save()
method that will persist it into a database. Let's say that your application executes the Person.Save()
method somewhere. If your DB refuses to save the Person, then .Save()
will throw an exception. Should you use throw
or throw e
in this case? Well, it depends.
What I prefer is doing:
try {
/* ... */
person.Save();
}
catch(DBException e) {
throw new InvalidPersonException(
"The person has an invalid state and could not be saved!",
e);
}
This should put the DBException as the "Inner Exception" of the newer exception being throw. So when you inspect this InvalidPersonException, the stack trace will contain info back to the Save method (that might be sufficient for you to solve the problem), but you still have access to the original exception should yuo need it.
As a final remark, when you are expecting an exception, you should really catch that one specific exception, and not a general Exception
, ie, if you are expecting an InvalidPersonException you should prefer:
try { ... }
catch (InvalidPersonException e) { ... }
to
try { ... }
catch (Exception e) { ... }
Good luck!
The difference between a parameterless catch and a catch(Exception e)
is that you get a reference to the exception. From framework version 2 unmanaged exceptions are wrapped in a managed exception, so the parameterless exception is no longer useful for anything.
The difference between throw;
and throw e;
is that the first one is used to rethrow exceptions and the second one is used to throw a newly created exception. If you use the second one to rethrow an exception, it will treat it like a new exception and replace all stack information from where it was originally thrown.
So, you shold not use either of the alternatives in the question. You should not use the parameterless catch, and you should use throw;
to rethrow an exception.
Also, in most cases you should use a more specific exception class than the base class for all exceptions. You should only catch the exceptions that you anticipate.
try {
...
} catch (IOException e) {
...
throw;
}
If you want to add any information when rethrowing the exception, you create a new exception with the original exception as an inner exception to preservere all information:
try {
...
} catch (IOException e) {
...
throw new ApplicationException("Some informative error message", e);
}