Handling errors

How to:

Let’s start with a try-catch block. It’s like putting a safety net under a tightrope walker. If they slip, they don’t plummet—they’re caught.

using System;

class ErrorHandlingExample {
    static void Main() {
        try {
            int[] numbers = {1, 2, 3};
            Console.WriteLine(numbers[5]);  // Oops, index is out of bounds!
        } catch (IndexOutOfRangeException e) {
            Console.WriteLine("Caught an error: " + e.Message);

Sample output when things go south:

Caught an error: Index was outside the bounds of the array.

Now we add a finally block—it’s what happens no matter what, like paying taxes.

try {
    // Potentially troublesome code here
} catch (SomeSpecificException e) {
    // Handle that specific error here
} finally {
    // This code runs no matter what happens above
    Console.WriteLine("This always runs.");

Deep Dive

Error handling’s been in C# since its birth. Over time, it’s evolved. Back in the day, programmers relied on return codes or global flags to signal problems—clunky and error-prone.

C# uses exceptions, a more modern approach. An exception is thrown when the unexpected happens, just like throwing a flag on the play in football. Structured exception handling with try, catch, and finally blocks makes managing these moments clearer and cleaner than old-school error checking.

Alternatives? Sure. There’s the UnhandledExceptionEventHandler for exceptions that slip through. Or in async code, error handling turns a bit on its head with Task objects that carry their own baggage of exceptions.

Implementation details—akin to the fine print—matter. Exceptions can be costly, dragging down performance if thrown willy-nilly. So, we use them for exceptional cases, not everyday logic control.

See Also