try / catch / finally
Wrap risky code in a try block. One or more catch blocks handle specific exception types. The finally block always runs—perfect for cleanup code.
Exception basics
Exceptions.cs
try
{
int[] arr = { 1, 2, 3 };
Console.WriteLine(arr[10]); // IndexOutOfRangeException
}
catch (IndexOutOfRangeException ex)
{
Console.WriteLine($"Array error: {ex.Message}");
}
catch (Exception ex) // catch-all
{
Console.WriteLine($"Unexpected: {ex.Message}");
}
finally
{
Console.WriteLine("Cleanup runs regardless.");
}Custom Exceptions
Inherit from Exception (or a more specific class) to create domain-specific exceptions with extra context.
Custom exception
CustomEx.cs
public class InsufficientFundsException(decimal amount, decimal balance)
: Exception($"Cannot withdraw {amount:C2}; balance is {balance:C2}")
{
public decimal Amount { get; } = amount;
public decimal Balance { get; } = balance;
}
// Usage
try
{
throw new InsufficientFundsException(500m, 100m);
}
catch (InsufficientFundsException ex)
{
Console.WriteLine(ex.Message);
}Exception Filters
C# supports when clauses on catch blocks to filter by condition without re-throwing.
Exception filter
ExFilter.cs
try
{
// ... http call
}
catch (HttpRequestException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
{
Console.WriteLine("Resource not found (404)");
}
catch (HttpRequestException ex)
{
Console.WriteLine($"HTTP error: {ex.StatusCode}");
}