In Focus

C# Try Catch Statement

C# Try Catch. The try..catch statement in C# is used in exception handling. In this article, I'll explain the use of try-catch in a .NET application including try-catch-finally and try-catch-finally-throw.

The try-catch statement in C# is used in exceptions in C#. The try block holds the suspected code that may get exceptions. When an exception is thrown, the .NET CLR checks the catch block and checks if the exception is handled. One try block can have multiple catch blocks. A try catch statement can have other nested try catch statements.
 

The try..catch

 
In C#, the try..catch statement is responsible for exception handling. A typical try..catch block looks like Listing 1. The suspect code is placed inside the try block and catch declares an exception.
  1. try  
  2. {  
  3. // Suspect code  
  4.   
  5. }  
  6. catch (Exception e)  
  7. {  
  8. // Action after the exception is caught  
  9. }  
Listing 1.
 
Let’s take a look at the code in Listing 2, that divides an int with 0. We put the suspected code within the try block and catch the exception and generate a human readable error message in the catch block. 
  1. try  
  2. {  
  3. int i = 20;  
  4. // Suspect code  
  5. int result = i / 0;  
  6. }  
  7. catch (DivideByZeroException ex)  
  8. {  
  9. Console.WriteLine("Attempted divide by zero. {0}", ex.Message);  
  10. }  
Listing 2
 
Obviously, the code in Listing 2 will throw an exception. In this case, we already know the issue, so we can simply catch the exception but the core purpose of exception handling is, when we don’t know when the error might occur.
 
Now, let’s say you’ve to use a class written by other developer that has a method, DivideNumer. See Listing 3.
  1. static double DivideNumber(double num1, double num2)  
  2. {  
  3. if (num1 < num2)  
  4. num1 += 20;  
  5. return num1 / num2;  
  6. }  
Listing 3
 
This is ideal to use a try..catch because we’re not sure when an error may occur. See Listing 4
  1. try  
  2. {  
  3. int i = 20; int j = 0;  
  4. double result = DivideNumber(i, j);  
  5. }  
  6. catch (DivideByZeroException ex)  
  7. {  
  8. Console.WriteLine("Attempted divide by zero. {0}", ex.Message);  
  9. }  
Listing 4
 

Multiple catch blocks

 
C# allows to use multiple catch in a try..catch block to catch specific exceptions. Let’s take at the code in Listing 5, that may generate Stack overflow, divide by zero, and invalid cast exceptions. We can handle this using separate catch blocks for each exception type.
  1. try  
  2. {  
  3. string mystring = default;  
  4. mystring.Insert(0, "hello");  
  5.   
  6. int i = 20; int j = 0;  
  7. double result = DivideNumber(i, j);  
  8.   
  9. object obj = default;  
  10. int i2 = (int)obj; // Suspect of casting error  
  11.   
  12. }  
  13. catch (StackOverflowException ex)  
  14. {  
  15. Console.WriteLine("Overflow. {0}", ex.Message);  
  16. }  
  17. catch (DivideByZeroException ex)  
  18. {  
  19. Console.WriteLine("Attempted divide by zero. {0}", ex.Message);  
  20. }  
  21. catch (InvalidCastException ex)  
  22. {  
  23. Console.WriteLine("Invalid casting. {0}", ex.Message);  
  24. }  
Listing 5
 

Handle general exceptions

 
What if we don’t know what kind of exception we will get? In that case, we use the Exception class to handle all exceptions. See Listing 6. Any exceptions that are not caught by the previous catch blocks, will be handled by the Exception block.
  1. try  
  2. {  
  3. string mystring = default;  
  4. mystring.Insert(0, "hello");  
  5.   
  6. int i = 20; int j = 0;  
  7. double result = DivideNumber(i, j);  
  8.   
  9. object obj = default;  
  10. int i2 = (int)obj; // Suspect of casting error  
  11.   
  12. }  
  13. catch (StackOverflowException ex)  
  14. {  
  15. Console.WriteLine("Overflow. {0}", ex.Message);  
  16. }  
  17. catch (DivideByZeroException ex)  
  18. {  
  19. Console.WriteLine("Attempted divide by zero. {0}", ex.Message);  
  20. }  
  21. catch (InvalidCastException ex)  
  22. {  
  23. Console.WriteLine("Invalid casting. {0}", ex.Message);  
  24. }  
  25. catch (Exception ex)  
  26. {  
  27. Console.WriteLine("General exception. {0}", ex.Message);  
  28. }  
Listing 6
 

The try..finally

 
When an exception occurs in a try block, the program control goes to the catch block if the exception is handled; otherwise, the program execution stops. But often we require some code to be executed even when an exception occurs. One of the key purposes of the "finally" block is to clean up any resources that were used in the try block. For example, if an IO resource is used to open and read a file, the IO resource must be released.
 
The code in Listing 7 creates a FileStream and reads a file that is not there. Obviously, the code will throw an exception that is not handled. But we want to make sure the FileStream object is released so we call FileStream.Close() method in the finally block.
  1. // Pick a file that is not there  
  2. string path = "AFile.txt";  
  3. // Create a FileStream  
  4. FileStream fs = default;  
  5. try  
  6. {  
  7. byte[] b = new byte[1024];  
  8. UTF8Encoding temp = new UTF8Encoding(true);  
  9. // Open FileStream  
  10. fs = File.Open(path, FileMode.Open);  
  11. // Read a file that is not there  
  12. while (fs.Read(b, 0, b.Length) > 0)  
  13. {  
  14. Console.WriteLine(temp.GetString(b));  
  15. }  
  16. }  
  17. finally  
  18. {  
  19. Console.WriteLine("Clean up start!");  
  20.   
  21. // Release resources here  
  22. fs.Close();  
  23. }  
Listing 7
 

The try..catch..finally

 
The complete exception handling syntax is try..catch..block that makes sure the exceptions are caught and any resources are cleaned up. Listing 8 is an example of using a try..catch..finally block.
  1. // Pick a file that is not there  
  2. string path = "AFile.txt";  
  3. // Create a FileStream  
  4. FileStream fs = default;  
  5. try  
  6. {  
  7. byte[] b = new byte[1024];  
  8. UTF8Encoding temp = new UTF8Encoding(true);  
  9. // Open FileStream  
  10. fs = File.Open(path, FileMode.Open);  
  11. // Read a file that is not there  
  12. while (fs.Read(b, 0, b.Length) > 0)  
  13. {  
  14. Console.WriteLine(temp.GetString(b));  
  15. }  
  16. }  
  17. catch(FileNotFoundException ex)  
  18. {  
  19. Console.WriteLine("FileNotFound. {0}", ex.Message);  
  20. }  
  21. finally  
  22. {  
  23. Console.WriteLine("Clean up start!");  
  24.   
  25. // Release resources here  
  26. fs.Close();  
  27. }  
Listing 8
 

The throw statement

 
Exceptions are usually thrown by the runtime but C# has the flexibility to throw exceptions manually. A library creator can throw exceptions when certain conditions are not met and a caller program can catch the exceptions.
 
The following syntax throws an exception.
 
throw Exception;
 
The code in Listing 9 declares a class, MathOps that contains two methods, FindPrimeNumber and DivideNumber and both of these methods throw two different exceptions.
  1. using System;  
  2.   
  3. namespace ExceptionThrowSample  
  4. {  
  5. class MathOps  
  6. {  
  7. // Create an array of numbers  
  8. int[] primes = { 2, 3, 5, 7, 11, 13, 17, 19 , 23, 29 };  
  9.   
  10. public int FindPrimeNumber(int index)  
  11. {  
  12. if (index < 0 || index >= primes.Length)  
  13. {  
  14. throw new IndexOutOfRangeException();  
  15. }  
  16. return primes[index];  
  17. }  
  18.   
  19. public double DivideNumber(int num1, int num2)  
  20. {  
  21. // If num2 is 0, throw an exception  
  22. if (num2 == 0)  
  23. throw new DivideByZeroException();  
  24. if (num1 < num2)  
  25. num1 += 20;  
  26. return num1 / num2;  
  27. }  
  28. }  
  29. }  
Listing 9.
 
The Listing 10 is a caller program that calls MathOps class and its methods and catches exceptions using two different catch blocks.
  1. using System;  
  2.   
  3. namespace ExceptionThrowSample  
  4. {  
  5. class Program  
  6. {  
  7. static void Main(string[] args)  
  8. {  
  9. var ops = new MathOps();  
  10.   
  11. // Create a random number  
  12. Random rand = new Random();  
  13. int index = rand.Next();  
  14. try  
  15. {  
  16. int prime = ops.FindPrimeNumber(index);  
  17. Console.WriteLine($"Number is {prime}");  
  18.   
  19. ops.DivideNumber(prime, index);  
  20. }  
  21. catch (IndexOutOfRangeException ex)  
  22. {  
  23. Console.WriteLine(ex.Message);  
  24. }  
  25. catch(DivideByZeroException ex)  
  26. {  
  27. Console.WriteLine(ex.Message);  
  28. }  
  29.   
  30. Console.ReadKey();  
  31. }  
  32. }  
  33. }  
Listing 10.
 

Throw expressions (C# 7)

 
So far, we’ve seen the use of throw keyword as a statement but starting with C# 7, the throw keyword can also be used as an expression. Now, with the use of an expression, the simple condition can be used in the same line that makes the code more readable and cleaner.
 
The code example in Listing 11 throws an exception based on a condition.
  1. public int FindPrimeNumber(int index)  
  2. {  
  3. if (index < 0 || index >= primes.Length)  
  4. {  
  5. throw new IndexOutOfRangeException();  
  6. }  
  7. return primes[index];  
  8. }  
Listing 11.
 
Now, using a throw expression, Listing 11 can be replaced with Listing 12.
  1. public int FindPrimeNumber(int index)  
  2. {  
  3. return ((index > 0) || index >= primes.Length) ? primes[index] :  
  4. throw new IndexOutOfRangeException();  
  5. }  
Listing 12.
 

Summary

 
In this article, I discussed how to use a try-catch statement in C#.
 
Next recommended article - Exception Handling in C# and Try Catch Finally in C#.