English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Here, you will learn how to use try, catch, and finally blocks for exception handling in C#.
Exceptions must be handled in the application to prevent program crashes and unexpected results, log exceptions, and continue executing other functions. C# provides built-in support for handling exceptions using try, catch, and finally blocks.
Syntax:
try { // Code placed here may cause an exception } catch { // Handle exceptions here } finally { // Final cleanup code }
Try block:Any code that may throw an exception should be placed within a try{ } block. During execution, if an exception occurs, the control flow jumps to the first matching catch block.
catch Block:The catch block is an exception handling block where you can perform some operations, such as logging and auditing exceptions. The catch block takes an exception type parameter, which you can use to obtain detailed information about the exception.
finally Block:The finally block will always execute regardless of whether an exception is thrown. Typically, finally should be used in a block to release resources, such as closing any streams or file objects opened in the try block.
If you enter a non-numeric character, the following content may cause an exception.
class Program { static void Main(string[] args) { Console.WriteLine("Enter a number: "); var num = int.Parse(Console.ReadLine()); Console.WriteLine($"Square of {num} is {num"); * num"); } }
To handle possible exceptions in the above example, wrap the code in a try block and then handle the exception in the catch block as shown below.
class Program { static void Main(string[] args) { try { Console.WriteLine("Enter a number: "); var num = int.parse(Console.ReadLine()); Console.WriteLine($"Square of {num} is {num"); * num"); } catch { Console.Write("Error occurred."); } finally { Console.Write("Re");-try with a different number."); } } }
In the above example, we wrap this code in a try block. If an exception occurs within the try block, the program will jump to the catch block. Within the catch block, we display a message to indicate to the user information about their error, and in the finally block, we display a message about operations after running the program.
The try block must be followed by catch or finally or both nested blocks. If the try block does not use a catch or finally block, a compile-time error will be given.
Ideally, the catch block should include parameters of built-in or custom exception classes to obtain detailed error information. Below includes the type parameter of Exception which captures all types of exceptions.
class Program { static void Main(string[] args) { try { Console.WriteLine("Enter a number: "); var num = int.parse(Console.ReadLine()); Console.WriteLine($"Square of {num} is {num"); * num"); } catch(Exception ex) { Console.Write("Error info:"); + ex.Message); } finally { Console.Write("Re");-try with a different number."); } } }
You can use multiple blocks with different exception type parameters for catch. This is called an exception filter. It is very useful when you want to handle different types of exceptions in different ways.
class Program { static void Main(string[] args) { Console.Write("Please enter a number to divide 100:"); try { int num = int.Parse(Console.ReadLine()); int result = 100 / num; Console.WriteLine("100 / {0} = {1} } catch(DivideByZeroException ex) { Console.Write("Cannot be divided by zero. Please try again."); } catch(InvalidOperationException ex) { Console.Write("Invalid operation. Please try again."); } catch(FormatException ex) { Console.Write("Invalid format. Please try again."); } catch(Exception ex) { Console.Write("An error occurred! Please try again."); } } }
In the above example, we specified multiple blocks with different exception types for catch. We can display an appropriate message to the user based on the error, so that the user will not repeat the same error again.
A parameterless catch block and a catch block with Exception parameter are not allowed in the same try..catch statement, because they both perform the same operation.
try { //Code that may cause an exception } catch //You cannot have both catch and catch (Exception exception) at the same time. { Console.WriteLine("Exception occurred"); } catch(Exception ex) //You cannot have both catch and catch (exception exception) at the same time. { Console.WriteLine("Exception occurred"); }
Additionally, the parameterless catch block catch {} or the general catch block catch (Exception ex){} must be the last block. If there are other catch blocks after the catch {} or catch (Exception ex) block, the compiler will produce an error.
Example: Invalid catch block capture
try { //Code that may cause an exception } catch { // The catch block must be the last block } catch(NullReferenceException nullEx) { Console.WriteLine(nullEx.Message); } catch(InvalidCastException inEx) { Console.WriteLine(inEx.Message); }
The finally block is an optional block that should be placed after the try or catch block. The finally block will always be executed regardless of whether an exception occurs. The finally block is usually used for cleanup code, such as handling unmanaged objects.
Example: finally block
static void Main(string[] args) { FileInfo file = null; try { Console.Write("Enter a file name to write: "); string fileName = Console.ReadLine(); file = new FileInfo(fileName); file.AppendText("Hello World!") } catch(Exception ex) { Console.WriteLine("Error occurred: {0}", ex.Message); } finally { // Here, clean up the file object; file = null; } }
finally cannot be used multiple blocks. In addition, the finally block cannot contain return, continue, or break keywords. It does not allow control to leave the finally block.
C# allows nested try-catch block. When using nested try-When a catch block occurs, the exception will be caught in the first matching block after the try block where the exception occurred.
static void Main(string[] args) { var divider = 0; try { try { var result = 100/divider; } catch { Console.WriteLine("Inner catch"); } } catch { Console.WriteLine("Outer catch"); } }
Inner catch
In the above example, the inner block will be executed because it is the first block to handle all exception types.
If there is no inner catch block that matches the type of the thrown exception, control will flow to the outer catch block until a suitable exception filter is found. See the following example.
static void Main(string[] args) { var divider = 0; try { try { var result = 100/divider; } catch(NullReferenceException ex) { Console.WriteLine("Inner catch"); } } catch { Console.WriteLine("Outer catch"); } }
Outer catch
In the above example, a DivideByZeroException will be thrown. Since the internal catch block only handles NullReferenceTypeException, it will be handled by the external catch block.