# Exceptions — C#/.NET

Source: https://www.skillbyai.com/en/dotnet/r-errors

> Throw, catch and design exceptions without hiding bugs.

## Exceptions are for exceptional cases

An **exception** signals that a method cannot do what its name promises. Throw built-in types where they fit (`ArgumentException`, `ArgumentNullException`, `InvalidOperationException`, `KeyNotFoundException`), and the guard helpers such as `ArgumentNullException.ThrowIfNull(x)` keep checks short. Catch an exception only where you can **handle** it: retry, fall back, translate it into a meaningful error, or log it at a boundary. Catch **specific** types before general ones, and use **exception filters** (`catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.NotFound)`) to catch conditionally. To rethrow, write **`throw;`**, which preserves the original stack trace; `throw ex;` resets it and hides where the error started. **`finally`** runs whether or not an exception occurred. Do not use exceptions for normal control flow: expected outcomes such as invalid user input are better served by `TryParse`-style methods or result types.

## Good and bad exception handling

Only catch what you can handle; let the rest reach a global handler.

```cs
async Task<Product?> LoadProductAsync(string id, CancellationToken ct)
{
    ArgumentException.ThrowIfNullOrWhiteSpace(id);
    try
    {
        return await _api.GetProductAsync(id, ct);
    }
    catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.NotFound)
    {
        return null;                       // an expected case, handled
    }
    catch (HttpRequestException ex)
    {
        _logger.LogWarning(ex, "Catalogue call failed for {ProductId}", id);
        throw;                             // keep the original stack trace
    }
}

// avoid:
// try { ... } catch (Exception) { }      // swallows every bug silently
```

## A fire alarm, not a doorbell

Exceptions are fire alarms: loud, expensive and reserved for real emergencies. Using them to announce visitors (expected situations) means people stop paying attention, and the cost adds up.

**Quiz:** Why prefer `throw;` over `throw ex;` when rethrowing?

- [ ] throw; is faster to type
- [ ] throw ex; does not compile
- [ ] throw; converts the exception to a warning
- [x] throw; preserves the original stack trace

*Answer:* throw; preserves the original stack trace. throw ex; resets the stack trace to the current location, hiding the real origin.
