21 Mar, 2009 · 8 minutes read
There are three types of errors that can occur in your application. These are:-
Syntax errorsoccur due to ill-formed codes. The cause can be a misspelled keyword, improperly constructed statements, absence of punctuations, such as line terminators, etc. The resulting code cannot be until all of these errors are removed.
Example:-
In this case the keyword Class is misspelled as Clas. Notice how the Visual Studio IDE highlights the error even before compilation starts. This is possible because of background compiling which is utilized in almost all modern Programming IDEs.
Runtime errors or Exceptionsare erroneous situations in the runtime. The simplest example can be a division by Zero which results in a “Division by Zero” exception to be raised. These are different from Syntax errors in the sense that the compiler cannot detect these and hence the application compiles.
Click on the image to see the full screen version.
In the above program, the application halts due to a DivideByZeroException. Since, the compiler cannot determine the number that will be entered by the user, the error goes undetected. At runtime, the statement float Result = I / J;raises the DivideByZero exception, if the user enters 0 as the input for the second variable.
Logical Errorsare those where the application compiles and runs properly but does not produce the required output, i.e errors in the logic of the program. They are harder to detect because they don’t throw any kind of exception. The best way to deal through them is to use the debugger, watches and call stacks.
System.Exceptionis the base class for all other exceptions. Below this level are the System.ApplicationExceptionand System.SystemExceptionclasses which are derived from the System.Exceptionclass.
The SystemExceptionclass acts as the base class for all the pre-defined Exceptions. ApplicationExceptionclass is to be used for any custom exceptions that you are to create in your application. Unlike the System Exceptions, these are forwarded by the application and not the CLR.
Below is a table listing some of the classes dervied from SystemExceptionclass.
Exception Class | Description |
---|---|
System.IO.IOException | Handles Input/Output errors |
System.IndexOutOfRangeException | Handles errors generated when a method refers to an array element, which is out of its bound. |
System.NullReferenceException | Hanldes errors generated during the process of dereferencing a null object. |
System.DivideByZeroException | Handles errors generated during the process of dividing a number by zero. |
InvalidCastException | Handles errors generated during typecasting. |
OutOfMemoryException | Handles memory allocation to the application errors. |
Exceptions are handled by using exception handlers. These exception handlers divide the code in blocks.
The try Block
All the codes that have a chance of throwing exceptions are put inside the Try block. Given below is a simple try block code.
try
{
//Statements that may throw exceptions.
}
The catch Block
If any statement inside the try block throws an exception, the execution control is passed onto the appropriate catch block. This allows the application to recover from exceptions. Catch block follows the following syntax:-
catch (…)
{
//Error Handling Code
}
Note: Every try block must have an associated catch block and vice versa.
The following code would trap the exception thrown in the previous example.
try
{
float Result = I / J;
}
catch
{
Console.WriteLine("An error occured while trying to compute the result");
}
Whenever the user enters a value of 0 for J, an exception would be thrown. Since, this code is contained in a try block, the code inside the catch block will be executed and a message An error occured while trying to compute the resultwill be shown to the user.
In the above example, the type of exception being thrown is unknown. So, no matter what exception is thrown, the same message will be displayed.
You can specify the type of exception a catch block handles in the following way:-
try
{
Result = Convert.ToInt32(I / J);
}
catch (DivideByZeroException)
{
Console.WriteLine("You tried to divide the number by zero");
}
The catch block declaration can also instantiate an object of the corresponding Exception class providing access to exception specific information – Error Codes, Description, etc.
try
{
Result = Convert.ToInt32(I / J);
}
catch (DivideByZeroException ex)
{
Console.WriteLine(ex.Message);
}
The code given below is a modified form of the earlier example.
Console.WriteLine("Enter Two Numbers:-");
int I = Convert.ToInt32(Console.ReadLine());
double J = Convert.ToDouble(Console.ReadLine());
int Result = 0;
try
{
Result = Convert.ToInt32(I / J);
}
catch
{
Console.WriteLine("An error occured while trying to compute the result");
}
Console.WriteLine("The result is {0}", Result);
Console.Read();
Line 8 can now generate two types of exception: DivieByZeroExceptionand OverflowException. When the user enters a very high value, say 65536275 for the variable Iand an extremely low value, say 0.0000001 for J. The result would exceed the range of the intdatatype and the OverflowException would be thrown. Because the user would be treated with the same error message, he/she might not be able to determine the exact cause of the error.
This is where the catch block comes in handy. Multiple catch blocks can be attached to a try block. Each of them should differ in the type of exception they handle.
Console.WriteLine("Enter Two Numbers:-");
int I = Convert.ToInt32(Console.ReadLine());
double J = Convert.ToDouble(Console.ReadLine());
int Result = 0;
try
{
Result = Convert.ToInt32(I / J);
}
catch (DivideByZeroException)
{
Console.WriteLine("You tried to divide the number by zero");
}
catch (OverflowException)
{
Console.WriteLine("The operation resulted in an overflow");
}
catch(Exception)
{
Console.WriteLine("An error occured while trying to compute the result");
}
Console.WriteLine("The result is {0}", Result);
Console.Read();
Now, if an OverflowException is thrown, the message The operation resulted in an overflowwill be displayed. For the DivideByZero exception, the message You tried to divide the number by zerowill be shown. For any other exception, the last message An error occured while trying to compute the resultwill be displayed.
Order of Catch Blocks
int A = 5, B = 0;
try
{
A = A / B;
}
catch (Exception ex)
{
Console.Write("Exception");
}
catch (DivideByZeroException ex)
{
Console.Write("Divide By Zero Exception");
}
The order of the catch block is very important.
A series of catch statements needs to be in decreasing order of derivation. For example, the most derived objects must appear first.
The above code generates the following compile-error: A previous catch clause already catches all exceptions of this or of a super type (‘System.Exception’).
If the catch(Exception) block is declared at the top, even a DivideByZeroException or the OverflowException will be handled by this block. This is because both of them are indirectly derived from the Exception class. Infact, C# does not allow such scenarios. So, you must first declare the exception class that is at a deeper level of the hierarchy.
The correct code would be as follows:-
int A = 5, B = 0;
try
{
A = A / B;
}
catch (DivideByZeroException ex)
{
Console.Write("Divide By Zero Exception");
}
catch (Exception ex)
{
Console.Write("Exception");
}
The finally block
This block is used to execute statements which are to be executed regardless of whether the exception is thrown or not. This may include a code such as to close a file, an existing SQL connection, etc. Only one finally block can exist for a try block. Also, the finally block is optional.
One may argue as to why we need the finally block because all statements below the entire try – catch block will be executed, irrespective of whether an exception is thrown or not. However, the code in the finally block is executed, even if a return statement is encountered inside the try or the catch block. The same is not true for the codes following the try – catch block.
int I = 10, J = 0;
float Result = 0;
try
{
Result = I / J;
}
catch
{
Console.WriteLine("An error occured while trying to compute the result");
return;
}
Console.WriteLine("The result is {0}", Result);
Console.Read();
The output of the preceeding block of code would be:-
An error occured while trying to compute the result
int I = 10, J = 0;
float Result = 0;
try
{
Result = I / J;
}
catch
{
Console.WriteLine("An error occured while trying to compute the result");
return;
}
finally
{
Console.WriteLine("The result is {0}", Result);
Console.Read();
}
While, the output for this one would be:-
An error occured while trying to compute the result
The result is 0
User defined exceptions can be created by deriving from the System.ApplicationExceptionclass or from any other system defined class. You can also derive Exceptions from these user-defined classes. The ultimate thing is that the new Exception class should be derived (directly or indirectly) from the Exception class.
class MyException : ApplicationException
{
public MyException(string Message) : base(Message)
{
}
}
Use the throw statement to raise your exceptions. This process requires the creation of a new object of the appropriate Exception class.
throw new(MyException("My Exception was thrown"));
Even the system defined exceptions can be thrown in this fashion.
Never create and throw an object of System.Exception class