There are three types of errors that can occur in your application. These are:-

  • Syntax Errors
  • Runtime Errors or Exceptions
  • Logical Errors

Syntax errors occur 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 Exceptions are 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 Errors are 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.

Exceptions

System.Exception is the base class for all other exceptions. Below this level are the System.ApplicationException and System.SystemException classes which are derived from the System.Exception class.

The SystemException class acts as the base class for all the pre-defined Exceptions. ApplicationException class 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 SystemException class.

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.
Handling Exceptions

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 result will 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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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: DivieByZeroException and OverflowException. When the user enters a very high value, say 65536275 for the variable I and an extremely low value, say 0.0000001 for J. The result would exceed the range of the int datatype 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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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 overflow will be displayed. For the DivideByZero exception, the message You tried to divide the number by zero will be shown. For any other exception, the last message An error occured while trying to compute the result will be displayed.

Order of Catch Blocks

1
2
3
4
5
6
7
8
9
10
11
12
13
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:-

1
2
3
4
5
6
7
8
9
10
11
12
13
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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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

Creating Custom Exceptions

User defined exceptions can be created by deriving from the System.ApplicationException class 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.

1
2
3
4
5
6
7
class MyException : ApplicationException
{
    public MyException(string Message) : base(Message)
    {
 
    }
}
Raising Exceptions

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

No votes yet.
Please wait...