Error Handling in C#: try/catch and Beyond from A to Z

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Error Handling in C#: try/catch and Beyond: from A to Z



Any application, even one written by the most experienced developer, can encounter unforeseen situations: network failure, missing file on disk, division by zero, or invalid data input. In C# (.NET), the exception mechanism is used to manage such situations. In this article, we will cover everything you need to know about error handling: from the basic try/catch construct to creating your own exception types and modern best practices.



1. Basics: the try/catch/finally construct



In C#, error handling revolves around three key blocks: try, catch, and finally.



  • try — contains code that may throw an exception.
  • catch — catches and handles a specific exception.
  • finally — always executes, regardless of whether an exception occurred or not (usually for resource cleanup).


try{    int[] numbers = { 1, 2, 3 };    Console.WriteLine(numbers[5]); // IndexOutOfRangeException}catch (IndexOutOfRangeException ex){    Console.WriteLine($"Error: {ex.Message}");}finally{    Console.WriteLine("The finally block always executes.");}


You can use multiple catch blocks for different exception types. Handling goes from top to bottom, so more specific exceptions should be placed above general ones.



try{    // dangerous code}catch (DivideByZeroException ex){    Console.WriteLine("Division by zero!");}catch (Exception ex) // general catch{    Console.WriteLine($"An error occurred: {ex.Message}");}


2. Throwing Exceptions: the throw statement



Sometimes you need to explicitly report an incorrect situation. The throw statement is used for this. You can throw either a standard exception or your own.



public void ValidateAge(int age){    if (age < 0 || age > 150)    {        throw new ArgumentOutOfRangeException(nameof(age), "Age must be between 0 and 150.");    }    Console.WriteLine("Age is valid.");}


There is also the throw; construct (without arguments) — it is used inside a catch block to re-throw the same exception. This is useful when you want to log the error but do not want to suppress it.



try{    // code}catch (Exception ex){    Log.Error(ex); // log the error    throw;         // re-throw — the exception propagates further}


3. Creating Custom Exceptions



For business logic, it is often more convenient to use your own exception types. This makes the code more readable and allows you to precisely handle specific errors.



Rules for creating a custom exception:

  • Inherit the class from Exception (or from ApplicationException, but it is better to inherit from Exception).
  • Implement three standard constructors (parameterless, with a message, with a message and an inner exception).
  • It is recommended to add the Exception suffix to the class name.


public class UserNotFoundException : Exception{    public UserNotFoundException() { }

public UserNotFoundException(string message) : base(message) { }

public UserNotFoundException(string message, Exception inner) : base(message, inner) { }}

// Usagethrow new UserNotFoundException("User with ID 123 not found.");


4. Best Practices: how not to harm yourself and the project



Error handling is not just about wrapping everything in try/catch. Here are a few golden rules to follow in C# (.NET):

\

Blogs

Book Recommendations