Sunday, July 22, 2012

Difference between Throw exception and Throw



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