Codectionary / Developer documentation / C#

Exception Handling

C# uses exceptions to signal that something went wrong during execution. A try block wraps risky code, one or more catch blocks handle specific exception types, and an optional finally block always runs for cleanup, whether or not an exception occurred. Unlike Java, C# does not have checked exceptions - the compiler never forces you to catch or declare an exception, though catching specific, meaningful types is still best practice.

Syntax

try {\n  // risky code\n} catch (ExceptionType e) {\n  // handle it\n} finally {\n  // always runs\n}

Examples

Basic try / catch

Catching an exception instead of letting the program crash.

try
{
    int result = 10 / int.Parse("0");
}
catch (DivideByZeroException e)
{
    Console.WriteLine($"Error: {e.Message}");
}

Console.WriteLine("Program continues running");

Catching Multiple Exception Types

Handling different exceptions differently with multiple catch blocks.

void Process(string input)
{
    try
    {
        int number = int.Parse(input);
        int result = 100 / number;
        Console.WriteLine(result);
    }
    catch (FormatException)
    {
        Console.WriteLine($"Not a valid number: {input}");
    }
    catch (DivideByZeroException)
    {
        Console.WriteLine("Cannot divide by zero");
    }
}

Process("abc");  // Not a valid number: abc
Process("0");     // Cannot divide by zero
Process("5");     // 20

finally and using

Code in finally always executes; the using statement automatically disposes resources, even on exception.

void ReadFile()
{
    Console.WriteLine("Opening file...");
    try
    {
        throw new InvalidOperationException("File not found");
    }
    catch (InvalidOperationException e)
    {
        Console.WriteLine($"Error: {e.Message}");
    }
    finally
    {
        Console.WriteLine("Closing file...");  // always runs
    }
}

ReadFile();

Custom Exceptions

Defining and throwing your own exception type for domain-specific error handling.

public class InsufficientFundsException : Exception
{
    public InsufficientFundsException(string message) : base(message) { }
}

public class BankAccount
{
    private double _balance;
    public BankAccount(double balance) => _balance = balance;

    public void Withdraw(double amount)
    {
        if (amount > _balance)
            throw new InsufficientFundsException("Not enough funds for this withdrawal");
        _balance -= amount;
    }
}

BankAccount account = new BankAccount(100);
try
{
    account.Withdraw(200);
}
catch (InsufficientFundsException e)
{
    Console.WriteLine($"Transaction failed: {e.Message}");
}

Best practices

  • Catch specific exception types rather than a broad catch (Exception e), so unrelated bugs are not accidentally silenced
  • Use finally (or better, a using statement/declaration) for cleanup code that absolutely must run, like closing files or database connections
  • Create custom exception classes, deriving from Exception, for domain-specific errors that callers should be able to catch distinctly
  • Don't use exceptions for routine control flow when a simple if check (or TryParse-style pattern) would do - they carry real performance overhead

At a glance

Purpose
Applications on the .NET platform
File extension
.cs
Runs in
.NET runtime
Usually used with
.NET SDK and libraries

Specifications & further reading

Related C# documentation

Classes & Objects
A class is a blueprint for creating objects, bundling related data (fields/properties) and behavior (methods) together. C# is a fully object-oriented language - every application has at least one class, typically with a Main method as its entry point. An object is a specific instance of a class, created with the new keyword, with its own independent copy of the class's instance data.
Constructors
A constructor is a special method that runs automatically when an object is created with new, used to initialize the object's state. A constructor shares its name with the class and has no return type. C# supports constructor overloading (multiple constructors with different parameter lists) and constructor chaining with this(...), where one constructor calls another in the same class to avoid duplicating initialization logic.
Properties (get/set)
Properties are C#'s idiomatic way to expose class data through accessor-like syntax while still allowing controlled access via get and set. Unlike a plain public field, a property can validate a value before it's set, compute a value on the fly, or restrict access to read-only. Auto-implemented properties (using { get; set; } with no body) provide a concise shorthand when no custom logic is needed.
Access Modifiers
Access modifiers control the visibility of classes, fields, methods, and properties from other parts of a program. C# provides public (accessible from anywhere), private (accessible only within the declaring class - the default for class members), protected (accessible within the class and its subclasses), internal (accessible only within the same assembly/project), and combinations like protected internal and private protected.