C# try catch

A try-catch block is used to catch the exceptions generated from the code in the try block and handle it in catch block instead of making the problem stopped running with an error message.

The syntax of try-catch block is shown below.

try
{
	// Code may generate exceptions
}
catch (<ExceptionClass 1> [e1])
{
	// Handle the exception
}
catch (<ExceptionClass 2> [e2])
{
	// Handle the exception
}
...
catch (<ExceptionClass n> [en])
{
	// Handle the exception
}

The code in the try block is evaluated at runtime first. If there is no exception thrown, the control will go to the statement behind catch blocks. Otherwise, we'll check all the catch blocks until the exception is caught. If it is caught, the code to handle the exception will be run and the control will go to the next statement behind catch blocks after running; If it is not caught, the exception will be thrown to the calling methods until it is caught. At last, if the exception has never been caught, the program will stop running with an error message.

Example 01-85-01

This is from the example 01-84-05, we'll add try-catch block to catch the exception.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;

class Program
{
    public int i;

    static void Main()
    {
        try
        {
            Program p = null;
            p.i = 10;   // NullReferenceException is issued
            Console.WriteLine("p.i = ", p.i);
        }
        catch (NullReferenceException e)
        {
            Console.WriteLine("Error: {0}", e.Message);
        }

        Console.Read();
    }
}

Output

Error: Object reference not set to an instance of an object.

Explanation

  • Line 12: NullReferenceException is generated in try block.
  • Line 13: This statement has never been run because an exception was generated in previous line and the control goes to catch block.
  • Line 15: Catch block to catch the NullReferenceException which is generated in line 12.
  • Line 17: e is the object of NullReferenceException class. e.Message is the property of the class and it returns the description of the exception.

This is from the example 01-84-05, we'll add try-catch block to catch the exception.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
using System;

class Program
{
    int total;
    int count;

    public Program(int total, int count)
    {
        this.total = total;
        this.count = count;
    }

    public int Average()
    {
        return Divide(total, count);
    }

    public int Divide(int a, int b)
    {
        return a / b;
    }

    static void Main()
    {
        // No Exceptions
        try
        {
            Program p = new Program(50, 5);
            Console.WriteLine("The average = {0}", p.Average());
        }
        catch (DivideByZeroException e)
        {
            Console.WriteLine("Error: {0}", e.Message);
        }
        Console.WriteLine("No Exception test is done.");

        // DivideByZeroException is generated
        try
        {
            Program p = new Program(50, 0);
            Console.WriteLine("The average = {0}", p.Average());
        }
        catch (DivideByZeroException e)
        {
            Console.WriteLine("Error: {0}", e.Message);
        }
        Console.WriteLine("DivideByZeroException test is done.");

        Console.Read();
    }
}

Output

The average = 10
No Exception test is done.
Error: Attempted to divide by zero.
DivideByZeroException test is done.

Explanation

  • Line 27-35: try-catch block but there is no exception thrown so the control will jump the catch block and go to the statement in line 36 after running in line 30.
  • Line 39-47: try-catch block and DivideByZeroException is generated.
  • Line 16, 21, 42: DivideByZeroException is thrown in line 21 by CLR and then goes to its calling method in line 16. Still there is no try-catch block to catch the exception then the control goes to line 42.
  • Line 44-47: The exception was caught here.
  • Line 48: The statement is executed after handling the exception.

The exception variables in the catch clause can be omitted or even more the whole arguments can be removed. The catch clause without arguments can catch any type of exceptions so it is only placed at the end of catch clauses.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
using System;

class Program
{
    static void throwInvalidCastException()
    {
        object o = 100;
        string s = (string)o;   // InvalidCastException is thrown
    }

    static void throwIndexOutofRangeException()
    {
        int[] a = new int[3];
        a[3] = 3;   // IndexOutOfRangeException is thrown
    }

    static void Main()
    {
        try
        {
            throwInvalidCastException();
        }
        catch (InvalidCastException)
        {
            Console.WriteLine("Catch an InvalidCastException.");
        }
        catch
        {
            Console.WriteLine("Catch any exceptions.");
        }

        try
        {
            throwIndexOutofRangeException();
        }
        catch (InvalidCastException)
        {
            Console.WriteLine("Catch an InvalidCastException.");
        }
        catch
        {
            Console.WriteLine("Catch any exceptions.");
        }

        Console.Read();
    }
}

Output

Catch an InvalidCastException.
Catch any exceptions.

Explanation

  • Line 5-9: Throw an InvalidCastException.
  • Line 11-15: Throw an IndexOutOfRangeException.
  • Line 19-30: Catch the InvalidCastException thrown in line 8.
  • Line 23: The exception variable in the argument is omitted.
  • Line 32-43: Catch the IndexOutofRangeException thrown in line 14.
  • Line 40-43: The exception is caught here. There is no argument in the catch block so it can catch all other exceptions which was not caught in the previous catch blocks.