What is the difference between Throw and Throw Exception in C#?
While implementing any application, usually we do throw/re-throwing of exceptions from catch block using the following,
1. catch(Exception ex) { throw ex; }
Before you go and change all of your code, there are still places where "throw ex" is appropriate. There are times when you want to add information to the exception that was caught and change it into a more meaningful exception. In these instances you actually want a new exception to be thrown.
Again, there are two ways to achieve this. The most common way that I have seen is,
Conclusion:
1. catch(Exception ex) { throw ex; }
OR
2.catch(Exception ex) { throw; }
Now, Let's see how these two are different and what is the use of each.
Exception handling seems to be a common problem for .NET
developers. We all know
that you should wrap operations that have the potential for failing in a
try/catch block if you are interested in being able to do something
about the error that occurred.
Here I am going to focus on a
particular aspect of exception handling, which I tend to call exception
bubbling. Exception bubbling means that, even though you are
catching the exception and doing something with it, you want that
exception to be "bubble" up from your code to the calling code. So, it has a
chance to do something with that exception and very useful while tracking any issue in future.
I'm sure that, most of the exception handling code you've seen looks similar to this
1: try
2: {
3: // do some operation that can fail
4: }
5: catch (Exception ex)
6: {
7: // do cleanup as your need
8: throw ex;
9: }
The above code looks perfectly reasonable and does the job. It properly
catch the exception, does some cleanup and then bubbles up the
exception.
Note: In the real environment you should not catch the general exception as show above. You should be catching the specific exceptions(like SecurityException) and only
those that you can do something with that.
However, there is another way of handling errors that looks like this
1: try
2: {
3: // do some operation that can fail
4: }
5: catch (Exception ex)
6: {
7: // do cleanup as your need
8: throw;
9: }
There is a lot of difference between these two calls that won't be seen until you are trying to debug the problem. That difference is
in the stack trace information that gets sent with the exception.
In the first case, the stack trace is truncated below the method that
failed.i.e., when you look at the stack trace, it
will look as if the exception originated in your code. This isn't always
the case, particularly if you are bubbling up a CLR generated exception
(like a SqlException). This is a problem known as "breaking the stack",
because you no longer have the full stack trace information. This
happens because you are in essence creating a new exception to throw.
By using "throw" by itself, you can preserve the stack trace information.
You can confirm this by looking at the IL generated for these two code
blocks. This makes the difference very obvious since in the first
example the IL instruction called is "throw" while in the second the
instruction is called "rethrow".
Before you go and change all of your code, there are still places where "throw ex" is appropriate. There are times when you want to add information to the exception that was caught and change it into a more meaningful exception. In these instances you actually want a new exception to be thrown.
Again, there are two ways to achieve this. The most common way that I have seen is,
1: try
2: {
3: // do some operation that can fail
4: }
5: catch (Exception ex)
6: {
7: // do local cleanup as your need
8: throw new ApplicationException("Some meaning full message!");
9: }
However, this still suffers the problem of breaking the stack. Here
you are generating a completely new exception and loosing any of the
stack trace information from the original exception. Here, what you really
want to do is,
1: try
2: {
3: // do some operation that can fail
4: }
5: catch (Exception ex)
6: {
7: // do local cleanup as your need
8: throw new ApplicationException("Some meaning full message!", ex);
9: }
By passing the original exception to the ApplicationException you are
preserving the original exception, and it is stack trace information as
the inner exception to your ApplicationException.
Note: No need to use "ApplicationException" to rethrow error. Here it is used just for an example. You can use any custom exception, which can be created by inheriting from Exception class.
Conclusion:
- Catch only exceptions if they are important to you and you need to do some sort of cleanup as a result.
- If you need to bubble-up an exception, use "throw" by itself.
- If you want to add additional information to the exception, always pass the original exception as the inner exception.
Comments
Post a Comment