Skip to main content
C# Fundamentals for Beginners to Advanced
CHAPTER 19 Beginner

Exception Handling in C#

Updated: May 17, 2026
5 min read

# CHAPTER 19

Exception Handling

1. Introduction

No matter how perfectly you write your code, things will go wrong at runtime. A user types text when you asked for a number. A database server goes offline. A file is deleted. If you don't handle these Exceptions, your application will abruptly crash. Exception Handling allows you to intercept errors, report them gracefully, and keep the program running.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Understand the try, catch, and finally blocks.
  • Catch specific types of exceptions.
  • Use the throw keyword.
  • Ensure resources are cleaned up using finally.

3. The try and catch Blocks

  • try: A block of code you suspect might cause an error.
  • catch: The block of code that executes *only if* an error occurs inside the try block.
csharp
123456789101112131415161718192021222324
using System;

class Program
{
    static void Main()
    {
        try
        {
            Console.Write("Enter a number: ");
            // If the user types "Hello", Parse() will throw a FormatException!
            int num = int.Parse(Console.ReadLine()); 
            
            Console.WriteLine($"You entered: {num}");
        }
        catch (Exception ex) // Catches the error and stores data in 'ex'
        {
            // The program does not crash! It jumps here.
            Console.WriteLine("ERROR: You did not enter a valid number.");
            Console.WriteLine($"System Details: {ex.Message}");
        }
        
        Console.WriteLine("Program continues normally...");
    }
}

4. Catching Specific Exceptions

A try block can have multiple catch blocks. It is best practice to catch specific, anticipated errors first, and leave the generic Exception class at the bottom as a catch-all safety net.
csharp
1234567891011121314151617
try
{
    int[] numbers = { 10, 20, 30 };
    Console.WriteLine(numbers[5]); // Throws IndexOutOfRangeException
}
catch (IndexOutOfRangeException ex)
{
    Console.WriteLine("Error: Tried to access an invalid array index.");
}
catch (DivideByZeroException ex)
{
    Console.WriteLine("Error: Cannot divide by zero.");
}
catch (Exception ex) // The generic catch-all MUST be last
{
    Console.WriteLine($"Unknown error: {ex.Message}");
}

5. The finally Block

The finally block is placed after the catch blocks. The code inside finally is GUARANTEED to execute, regardless of whether an exception occurred or not. It is typically used to close database connections or open files, ensuring memory isn't locked.
csharp
123456789101112131415
try
{
    Console.WriteLine("Opening file...");
    // Simulate error
    throw new Exception("File corrupted!"); 
}
catch (Exception ex)
{
    Console.WriteLine("Caught an error.");
}
finally
{
    // This will print even though an error occurred!
    Console.WriteLine("Closing file..."); 
}

6. The throw Keyword

You can manually trigger an exception if your code detects a logical error (e.g., an age cannot be negative).
csharp
123456789
static void CheckAge(int age)
{
    if (age < 0)
    {
        // Manually trigger an error
        throw new ArgumentException("Age cannot be negative.");
    }
    Console.WriteLine($"Age is {age}");
}

7. Mini Project: Safe Calculator

csharp
12345678910111213141516171819202122232425262728293031323334
using System;

namespace SafeCalculator
{
    class Program
    {
        static void Main()
        {
            try
            {
                Console.Write("Enter numerator: ");
                int num1 = int.Parse(Console.ReadLine());

                Console.Write("Enter denominator: ");
                int num2 = int.Parse(Console.ReadLine());

                int result = num1 / num2;
                Console.WriteLine($"Result: {result}");
            }
            catch (FormatException)
            {
                Console.WriteLine("Error: Please enter numbers only.");
            }
            catch (DivideByZeroException)
            {
                Console.WriteLine("Error: Mathematics forbids division by zero.");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"An unexpected error occurred: {ex.Message}");
            }
        }
    }
}

8. Common Mistakes

  • Empty Catch Blocks: Writing catch (Exception) { } and doing nothing inside it is called "swallowing" the exception. It hides bugs and makes debugging impossible. At least log the error to the console!
  • Using Try-Catch for Control Flow: Do not use exceptions to control normal program logic. Exceptions are computationally expensive. Use an if statement to check if a string is null, don't just let it throw a NullReferenceException.

9. Best Practices

  • Catch specific exceptions (like FileNotFoundException) instead of always catching the generic Exception.
  • Use the ex.Message or ex.StackTrace properties to log detailed information for debugging.

10. Exercises

  1. 1. Write a program that accesses the 10th element of a 3-element array. Wrap it in a try-catch block that specifically catches IndexOutOfRangeException.
  1. 2. Add a finally block that prints "Execution finished."

11. MCQs with Answers

Question 1

Which block contains the code that might cause a runtime error?

Question 2

Which block contains the code that handles the error?

Question 3

Which block is guaranteed to execute, regardless of whether an error occurred or not?

Question 4

Which keyword is used to manually generate an exception?

Question 5

What is the base class for all exceptions in C#?

Question 6

What happens if an exception is thrown but there is no catch block to handle it?

Question 7

When chaining multiple catch blocks, where must the generic catch (Exception ex) be placed?

Question 8

Which exception is thrown when you divide an integer by 0?

Question 9

Which exception is thrown when int.Parse() fails to convert letters to a number?

Q10. Is it good practice to leave a catch block completely empty? a) Yes, it cleans up the console b) No, it "swallows" the error and makes debugging impossible Answer: b) No, it "swallows" the error and makes debugging impossible

12. Interview Questions

  • Q: Explain the exact execution flow of try, catch, and finally.
  • Q: Why should you avoid catching the generic Exception base class if possible?
  • Q: What is the difference between throw; and throw ex; inside a catch block? (Answer: throw; preserves the original stack trace, while throw ex; resets the stack trace to the catch block, making debugging harder).

13. Summary

Exception handling acts as a safety net. The try block attempts risky code, the catch block gracefully intercepts and manages crashes, and the finally block ensures critical cleanup happens no matter what. Using throw, you can manually enforce logical rules in your application.

14. Next Chapter Recommendation

In Chapter 20: Generics and Collections, we will revisit List<T> and explore how the <T> syntax (Generics) allows us to write highly reusable, type-safe data structures.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·