Roadmap › C# Language — Basics to Advanced › Module: Errors, Resources and Memory
Lessons in this course (38)
28. Built-in exceptions, throw and custom exceptions
Basic★ Must knowLesson 28 of 38
Exception hierarchy: everything derives from System.Exception. Common built-in exceptions:
| Exception | Thrown when |
|---|---|
NullReferenceException | You use a member of a null reference |
ArgumentException / ArgumentNullException / ArgumentOutOfRangeException | A method receives an invalid argument (throw these yourself to validate input) |
InvalidOperationException | The object's state doesn't allow the call (e.g. modifying a list during foreach, First() on empty sequence) |
IndexOutOfRangeException | Array index outside its bounds |
KeyNotFoundException | Dictionary indexer with a missing key |
InvalidCastException | Bad explicit cast / unboxing to the wrong type |
FormatException | int.Parse("abc") |
OverflowException | checked arithmetic overflows |
DivideByZeroException | Integer division by zero (double gives Infinity instead) |
FileNotFoundException, DirectoryNotFoundException, IOException | File system problems |
NotImplementedException / NotSupportedException | Method not written yet / operation not supported by design |
TimeoutException, OperationCanceledException / TaskCanceledException | Timeouts and cancellation |
HttpRequestException | HttpClient call failed |
OutOfMemoryException, StackOverflowException | Runtime failures — the latter can't be caught and kills the process |
Throwing:
csharp
public void Withdraw(decimal amount)
{
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(amount); // .NET 8 throw helpers
if (amount > Balance) throw new InsufficientFundsException(Balance, amount);
Balance -= amount;
}
public Customer(string name) => Name = name ?? throw new ArgumentNullException(nameof(name)); // throw expression
try { Save(); }
catch (SqlException ex)
{
log.LogError(ex, "Save failed");
throw; // ✅ rethrow keeps the original stack trace
// throw ex; // ❌ resets the stack trace to this line
}Custom exception:
csharp
public class InsufficientFundsException : Exception
{
public decimal Balance { get; }
public decimal Requested { get; }
public InsufficientFundsException() { }
public InsufficientFundsException(string message) : base(message) { }
public InsufficientFundsException(string message, Exception inner) : base(message, inner) { }
public InsufficientFundsException(decimal balance, decimal requested)
: base($"Balance {balance} is less than requested {requested}.")
=> (Balance, Requested) = (balance, requested);
}
try { account.Withdraw(5000); }
catch (InsufficientFundsException ex) when (ex.Requested > 1000)
{
Console.WriteLine($"Large withdrawal refused: {ex.Message}");
}Guidelines: name ends with Exception; derive from Exception (not ApplicationException); add properties with useful data; create custom exceptions only when callers will catch them specifically — otherwise use the built-in ones.