I know most of the programmers including me use Throw
exception and Throw in our daily programming and we never see any side effects
because of our usage. But best practices always say that we need to know what
is good for a particular situation. And often many programmers gets confused between the two though they feel they know it. In fact I also think the same.
Basic difference is Throw exception overwrites the stack
trace and this makes it hard to find the original code line number that has thrown
the exception.
Throw basically keeps up the stack information and adds it
stack information in the exception that it is throwing.
Let us see what it means rather speaking so many words to
better understand the differences. I am using a console application to easily
test and see how the usage of two differs in their functionality.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestingThrowExceptions
{
class Program
{
public void ExceptionMethod()
{
throw new Exception("Original Exception occurred in ExceptionMethod");
}
static void Main(string[] args)
{
Program p = new Program();
try
{
p.ExceptionMethod();
}
catch (Exception ex)
{
throw ex;
}
}
}
}
Now run the code by pressing F5 button the key board and see
what happens. It returns an exception and look at the stack trace.
System.Exception was unhandled
Message=Original
Exception occurred in ExceptionMethod
Source=TestingThrowExceptions
StackTrace:
at
TestingThrowExceptions.Program.Main(String[] args) in
C:\TestProjects\TestingThrowExceptions\TestingThrowExceptions\Program.cs:line
26
You find that the exception source is shown as Main method
in the program.cs at line 26.
Now change the code with Throw instead of Throw exception
and see what happens.
Message=Original
Exception occurred in ExceptionMethod
Source=TestingThrowExceptions
StackTrace:
at
TestingThrowExceptions.Program.ExceptionMethod() in
C:\TestProjects\TestingThrowExceptions\TestingThrowExceptions\Program.cs:line
12
at
TestingThrowExceptions.Program.Main(String[] args) in C:\TestProjects\TestingThrowExceptions\TestingThrowExceptions\Program.cs:line
26
Now the stack trace shows that the exception original source
is ExceptionMethod() and then it shows the Main method.
If you observe both the stack traces the first one in blue
(for Throw Exception) and the second one in Green (for Throw), you will find
that the first one has truncated the original stack trace and throwing the
exception as if it is a source for the exception.
Basically in MSIL there are two types of instructions, Throw
and reThrow. “Throw exception” is compiled into Throw instruction and “Throw”
is compiled into rethrow.
So any time you re throw the exception using “Throw”
statement it preserves the original stack trace and if you re throw the
exception using “Throw ex” the stack trace is reset to the point where the
exception has been thrown.
Now I have modified to see what happens if the code has more
than one source of exception.
class Program
{
public void AnotherMethod()
{
Program p = new Program();
try
{
p.ExceptionMethod();
}
catch (Exception ex)
{
throw;
}
}
public void ExceptionMethod()
{
throw new Exception("Original Exception occurred in ExceptionMethod");
}
static void Main(string[] args)
{
Program p = new Program();
try
{
p.AnotherMethod();
}
catch (Exception ex)
{
throw;
}
}
}
I have added a method called “AnotherMethod()” which calls
the method “ExceptionMethod()” and the method “AnotherMethod()” has been called
in Main method to check if still the original stack trace is preserved and here
is the stack trace we got when we ran the program:
Message=Original
Exception occurred in ExceptionMethod
Source=TestingThrowExceptions
StackTrace:
at
TestingThrowExceptions.Program.ExceptionMethod() in C:\TestProjects\TestingThrowExceptions\TestingThrowExceptions\Program.cs:line
26
at
TestingThrowExceptions.Program.AnotherMethod() in
C:\TestProjects\TestingThrowExceptions\TestingThrowExceptions\Program.cs:line
20
at
TestingThrowExceptions.Program.Main(String[] args) in
C:\TestProjects\TestingThrowExceptions\TestingThrowExceptions\Program.cs:line
40
You observer that it has listed the source in order first
one as ExceptionMethod and then followed by AnotherMethod and then by Main
method.
So, then the question comes in our mind is when shall we use
the “Throw ex” in our code? The answer is when you want to throw a meaningful
exception to the calling method or code where the exception has been thrown by
the source of the exception. Then the second question is then how can we make
sure that what code in our program has raised an exception? The answer is by
adding the original exception as the inner exception.
Let us see it how by modifying the “Throw” in all of our
methods to “Throw exception” and add the original one as an inner exception.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestingThrowExceptions
{
class Program
{
public void AnotherMethod()
{
Program p = new Program();
try
{
p.ExceptionMethod();
}
catch (Exception ex)
{
throw new ApplicationException("operation failed",ex);
}
}
public void ExceptionMethod()
{
throw new Exception("Original Exception occurred in ExceptionMethod");
}
static void Main(string[] args)
{
Program p = new Program();
try
{
p.AnotherMethod();
}
catch (Exception ex)
{
throw new ApplicationException("Could not get data",ex);
}
}
}
}
Let us see the stack trace by running the program:
Message=Could not
get data
Source=TestingThrowExceptions
StackTrace:
(3)
at TestingThrowExceptions.Program.Main(String[] args) in C:\TestProjects\TestingThrowExceptions\TestingThrowExceptions\Program.cs:line
40
……
InnerException:
System.ApplicationException
Message=operation failed
Source=TestingThrowExceptions
StackTrace:
(2)
at TestingThrowExceptions.Program.AnotherMethod() in C:\TestProjects\TestingThrowExceptions\TestingThrowExceptions\Program.cs:line
20
(3)
at TestingThrowExceptions.Program.Main(String[] args) in
C:\TestProjects\TestingThrowExceptions\TestingThrowExceptions\Program.cs:line
35
InnerException:
Message=Original Exception occurred in
ExceptionMethod
Source=TestingThrowExceptions
StackTrace:
(1) at
TestingThrowExceptions.Program.ExceptionMethod() in C:\TestProjects\TestingThrowExceptions\TestingThrowExceptions\Program.cs:line
26
(2) at
TestingThrowExceptions.Program.AnotherMethod() in
C:\TestProjects\TestingThrowExceptions\TestingThrowExceptions\Program.cs:line
15
InnerException:
So, on looking at the stack trace, you can still be able to
find out where the exception has originally occurred.
If your application stores the meaningful application in
database or is to be displayed to the user on UI screen we should follow this
method and the actual stack trace should be logged in a log file for debugging
the code.
No comments:
Post a Comment