Lesson 10 of 40
Core C#
Intermediate
โฑ 30 min
Exception Handling & Error Patterns
Write robust code with try/catch/finally, custom exceptions, the Result pattern, and modern global exception filters.
Part 1: try / catch / finally
try
{
var data = await FetchDataAsync(url);
Process(data);
}
catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.NotFound)
{
_logger.LogWarning("Resource not found: {Url}", url);
}
catch (Exception ex)
{
_logger.LogError(ex, "Unexpected error");
throw; // Re-throw preserving stack trace
}
finally
{
Cleanup(); // Always runs
}
{
var data = await FetchDataAsync(url);
Process(data);
}
catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.NotFound)
{
_logger.LogWarning("Resource not found: {Url}", url);
}
catch (Exception ex)
{
_logger.LogError(ex, "Unexpected error");
throw; // Re-throw preserving stack trace
}
finally
{
Cleanup(); // Always runs
}
Part 2: Custom Exceptions
public class OrderNotFoundException : Exception
{
public int OrderId { get; }
public OrderNotFoundException(int id)
: base($"Order {id} not found") => OrderId = id;
}
// Throw it
throw new OrderNotFoundException(orderId);
{
public int OrderId { get; }
public OrderNotFoundException(int id)
: base($"Order {id} not found") => OrderId = id;
}
// Throw it
throw new OrderNotFoundException(orderId);
Part 3: Result Pattern (No Exceptions for Flow)
public readonly record struct Result<T>
{
public bool IsSuccess { get; }
public T? Value { get; }
public string? Error { get; }
public static Result<T> Ok(T v) => new() { IsSuccess=true,Value=v };
public static Result<T> Fail(string e) => new() { Error=e };
}
{
public bool IsSuccess { get; }
public T? Value { get; }
public string? Error { get; }
public static Result<T> Ok(T v) => new() { IsSuccess=true,Value=v };
public static Result<T> Fail(string e) => new() { Error=e };
}
Part 4: IDisposable & using Statements
// using ensures Dispose() is called
using var conn = new SqlConnection(connStr);
await conn.OpenAsync();
// conn.Dispose() called at end of scope automatically
// Implement IDisposable in your own classes
public class FileWriter : IDisposable
{
private readonly StreamWriter _writer;
public void Dispose() => _writer.Dispose();
}
using var conn = new SqlConnection(connStr);
await conn.OpenAsync();
// conn.Dispose() called at end of scope automatically
// Implement IDisposable in your own classes
public class FileWriter : IDisposable
{
private readonly StreamWriter _writer;
public void Dispose() => _writer.Dispose();
}
C# in Visual Studio 2026
๐ This lesson is part of the book C# in Visual Studio 2026 by Dr. Liew Voon Kiong.
View on Amazon Kindle Edition