SyntaxStudy
Sign Up
C# Beginner 1 min read

Custom Exceptions

Creating custom exception types lets you communicate domain-specific error conditions clearly and allows callers to catch them specifically. A custom exception should inherit from `Exception` (or a more specific built-in subclass) and provide constructors that delegate to the base class, including the three-constructor pattern for serialisation support. Add extra properties to carry contextual information. For example, a `ValidationException` might carry a `FieldName` and `AttemptedValue`. This makes catching code far more informative than reading a message string. Exception hierarchy design matters: group related exceptions under a common base class so callers can catch all variants at once or specific ones individually. Keep the hierarchy shallow — typically one or two levels is enough. Avoid creating a custom exception for every method; reserve them for error conditions that callers are likely to handle differently.
Example
// Custom exception hierarchy

// Base domain exception
public class DomainException : Exception
{
    public string DomainContext { get; }

    public DomainException(string message, string context)
        : base(message)
    {
        DomainContext = context;
    }

    public DomainException(string message, string context, Exception inner)
        : base(message, inner)
    {
        DomainContext = context;
    }
}

// Specific subclass with extra data
public class ValidationException : DomainException
{
    public string   FieldName      { get; }
    public object?  AttemptedValue { get; }

    public ValidationException(string field, object? value, string message)
        : base(message, context: "Validation")
    {
        FieldName      = field;
        AttemptedValue = value;
    }

    public override string ToString() =>
        $"[ValidationException] Field={FieldName}, Value={AttemptedValue}, Message={Message}";
}

// Usage
static void SetAge(int age)
{
    if (age < 0 || age > 150)
        throw new ValidationException(nameof(age), age, "Age must be between 0 and 150.");
}

try
{
    SetAge(-5);
}
catch (ValidationException ex)
{
    Console.WriteLine(ex);
    Console.WriteLine($"Context: {ex.DomainContext}");
}
catch (DomainException ex)
{
    Console.WriteLine($"Domain error [{ex.DomainContext}]: {ex.Message}");
}