Monday, August 25, 2008

Exception Handling Unplugged..!!

What is Exception Handling and why do we need it?

The mark of a good, robust program is planning for the unexpected, and recovering if it does happen. Errors can happen at almost any time during the compilation or execution of a program. We can detect and deal with these errors using Exception Handling. Exception handling is an in built mechanism in .NET framework to detect and handle run time errors. At the heart of the .NET Framework is the Common Language Runtime (CLR) which in addition to acting as a virtual machine and interpreting and executing IL code on the fly, performs numerous other functions such as type safety checking, memory management, garbage collection and Exception handling. The .NET framework contains lots of standard exceptions. It allows you to define how the system reacts in unexpected situations like 'File not found' , 'Out of Memory' , bad logic, non-availability of operating system resources other than memory, 'Index out of bounds' and so on.

When the code which has a problem, is executed, it 'raises an exception'. If a programmer does not provide a mechanism to handle these anomalies, the .NET run time environment provides a default mechanism, which terminates the program execution. This mechanism is a structured exception handling mechanism




Exceptions in C#

Exceptions in C# are represented by objects with type names representative of the type of error that occurred in the program. Exceptions in C# provide a structured, uniform, and type-safe way of handling both system level and application level error conditions. . In C#, all exceptions must be represented by an instance of a class type derived from System.Exception. System.Exception class is the base type of all exceptions.An object of an exception is that which describes the exceptional conditions occuring in a code that means, we are catching an exception, creating an object of it, and then throwing it.

Like other modern and structured programming languages, C# also provides a rich mechanism of Exception Handling. Exceptions are handled in C# using the 'try/catch/finally' statements. These keywords are also named as Structured Exception Handling (SEH). The code which 'may cause an exception' is enclosed within a 'try' block as shown below:

try
{
// this code may cause an exception.
}

Your code feels safe now as it has been protected. If an exception does occurs in the code enclosed within the 'try' block, you can handle it. To handle an exception, attach a 'catch' block to the 'try'.

try
{
// this code may cause an exception.
// If it does cause an exception, the execution will not continue.
// Instead,it will jump to the 'catch' block.
}
catch (Exception ex)
{
// I get executed when an exception occurs in the try block.
// Write the error handling code here.
}

Having understood the basic syntax, let's rewrite the example ShowingExceptions

// Example ShowingExceptions using structured exception handling the C# way.

class ShowingExceptions
{
static void main()
{
Console.Write("Please enter a number :");
string str = Console.ReadLine();
double dNo;
}
try
{
dNo = double.Parse(str);
Console.WriteLine("Parsing successfully without errors");
}
catch(Exception ex)
{
Console.WriteLine("Error : {0} is not a valid number", str);
}

}

Execution :
Please enter a number : Hello

Output:

Error: Hello is not a valid number.

Thus here we notice that when the exception does occur, the program stops executing code from the try block and immediately jumps to the catch block. This is why the output, " Parsing successfully without errors " is not displayed when the exception occurs.

NOTE:

It is not a good idea to display the raw exception message to the user. Instead, show a friendly message to the user and log the actual exception message to some log file for trouble shooting purposes.

Moreover, in the above example, we are handling all types of exceptions. But it is a bad practise to catch all exceptions. You should catch only specific exceptions which are expected in the specific code block. For example, if you are attempting to allocate the memory, you may catch 'System.OutOfMemoryException' and if you are performing mathematical operations, you may catch
'System.DivideByZeroException' exception. Also, you can create and throw custom exceptions.

Eg:



ArgEx ArgumentException = new ArgumentException("You entered bad data");
throw ArgEx;

Ok, But what about the finally block?

C# provides the finally block to enclose a set of statements that need to be executed regardless of the course of control flow. So as a result of normal execution, if the control flow reaches the end of the try block, the statements of the finally block are executed. Moreover, if the control leaves a try block as a result of a throw statement or a jump statement such as break , continue, or goto, the statements of the finally block are executed. The finally block is basically useful in three situations: to avoid duplication of statements, to release resources after an exception has been thrown and to assign a value to an object or display a message that may be useful to the program.

Let's see the example Showing Exceptions again:

// Example ShowingExceptions using finally
class ShowingExceptions
{
static void main()
{
Console.Write("Please enter a number :");
string str = Console.ReadLine();
double dNo;
}
try
{
dNo = double.Parse(str);
Console.WriteLine("Parsing successfully without errors");
}
finally
{
Console.WriteLine("Storing the number as 1.0");
dNo = 1.0; // dNo is assigned the value 1.0 irrespective of an error.
}
}

What are the other Exception Classes?

Here's a list of few Common Exception Classes:

System.ArithmeticException-A base class for exceptions that occur during arithmetic operations, such as System.DivideByZeroException


System.ArrayTypeMismatchException-Thrown when a store into an array fails because the actual type of the stored element is incompatible with the actual type of the array.


System.DivideByZeroException-Thrown when an attempt to divide an integral value by zero occurs.


System.IndexOutOfRangeException-Thrown when an attempt to index an array via an index that is less than zero or outside the bounds of the array.


System.InvalidCastExceptionThrown when an explicit conversion from a base type or interface to derived types fails at run time.


System.MulticastNotSupportedException-Thrown when an attempt to combine two non-null delegates fails, because the delegate type does not have a void return type.


System.NullReferenceException-Thrown when a null reference is used in a way that causes the referenced object to be required.


System.OutOfMemoryException-Thrown when an attempt to allocate memory (via new) fails.


System.OverflowException-Thrown when an arithmetic operation in a checked context overflows.