0Pricing
C# Academy · Lesson

Custom exceptions; error design

Create small custom exceptions, pick correct built-in types (ArgumentException, InvalidOperationException), and add context with InnerException.

Custom exceptions; error design is a free C# Academy lesson on CoddyKit — lesson 2 of 3. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the C# Academy learning path, one of 3 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Purpose & goals

Aim: Make errors clear and catchable.

  • Use a specific type for a specific failure
  • Good message + InnerException for context
  • Prefer built-ins when they fit

Custom exception type

Derive from Exception, end the name with Exception, and add the standard constructors. Carry small, useful data.

using System;

// Custom, specific to our domain
public sealed class ConfigNotFoundException : Exception
{
  public string Key { get; private set; }

  public ConfigNotFoundException(string key)
    : base("Config key not found: " + key)
  {
    Key = key;
  }

  public ConfigNotFoundException(string key, Exception inner)
    : base("Config key not found: " + key, inner)
  {
    Key = key;
  }
}

public class Program
{
  public static void Main(string[] args)
  {
    try
    {
      throw new ConfigNotFoundException("ApiUrl");
    }
    catch (ConfigNotFoundException ex)
    {
      Console.WriteLine(ex.Message);
    }
  }
}

InnerException for context

Wrap lower-level exceptions with a domain exception and set InnerException to keep the root cause.

using System;
using System.IO;

public sealed class ConfigNotFoundException : Exception
{
  public string Key { get; private set; }
  public ConfigNotFoundException(string key, Exception inner)
    : base("Config key not found: " + key, inner) { Key = key; }
}

public static class Config
{
  public static string Load(string path, string key)
  {
    try
    {
      string[] lines = File.ReadAllLines(path); // may throw
      for (int i = 0; i < lines.Length; i++)
      {
        int idx = lines[i].IndexOf("=");
        if (idx > 0 && lines[i].Substring(0, idx) == key)
          return lines[i].Substring(idx + 1);
      }
      throw new ConfigNotFoundException(key, null);
    }
    catch (IOException io)
    {
      // Wrap low-level error with domain meaning
      throw new ConfigNotFoundException(key, io);
    }
  }
}

public class Program
{
  public static void Main(string[] args)
  {
    try
    {
      Console.WriteLine(Config.Load("missing.cfg", "ApiUrl"));
    }
    catch (ConfigNotFoundException ex)
    {
      Console.WriteLine("Top: " + ex.Message);
      if (ex.InnerException != null)
        Console.WriteLine("Inner: " + ex.InnerException.GetType().Name);
    }
  }
}

Choose built-ins first

Use built-ins for common problems: ArgumentNullException, ArgumentOutOfRangeException, FormatException, InvalidOperationException, etc.

using System;

public static class MathUtil
{
  public static int Divide(int a, int b)
  {
    if (b == 0) throw new DivideByZeroException();
    return a / b;
  }

  public static int ParsePositive(string text)
  {
    if (text == null) throw new ArgumentNullException("text");
    int value = int.Parse(text); // may throw FormatException
    if (value <= 0) throw new ArgumentOutOfRangeException("text", "must be > 0");
    return value;
  }
}

public class Program
{
  public static void Main(string[] args)
  {
    try { Console.WriteLine(MathUtil.ParsePositive("-1")); }
    catch (ArgumentOutOfRangeException ex) { Console.WriteLine("Range: " + ex.ParamName); }
  }
}

Exceptions vs guards

Use exceptions for exceptional situations. For expected failures, prefer TryX guards or return codes.

using System;

public static class Parser
{
  // BAD: using exceptions for expected cases
  public static int ParseOrThrow(string s)
  {
    return int.Parse(s); // will throw often for user input
  }

  // GOOD: guard-check pattern for expected failure
  public static bool TryParsePositive(string s, out int value)
  {
    value = 0;
    int tmp;
    if (!int.TryParse(s, out tmp)) return false;
    if (tmp <= 0) return false;
    value = tmp;
    return true;
  }
}

public class Program
{
  public static void Main(string[] args)
  {
    int v;
    if (Parser.TryParsePositive("12", out v))
      Console.WriteLine("OK " + v);
    else
      Console.WriteLine("Invalid");
  }
}

Error design checklist

Checklist:

  • Pick a built-in type when possible.
  • Else create a small CustomException with standard ctors.
  • Attach InnerException to preserve root cause.
  • Use exceptions for unexpected cases; use TryX for expected failures.

Custom exception design

Quick check: What is a recommended design for a custom exception type in C#?

Recap

Recap: Prefer built-in exceptions; otherwise define a small custom type with standard constructors and use InnerException to add context without losing the cause.

Frequently asked questions

Is the “Custom exceptions; error design” lesson free?

Yes — the full text of “Custom exceptions; error design” is free to read here on the web, and the C# Academy course includes 3 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the C# Academy course, upgrade to CoddyKit PRO.

What will I learn in “Custom exceptions; error design”?

Create small custom exceptions, pick correct built-in types (ArgumentException, InvalidOperationException), and add context with InnerException. You practise C# Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start C# Academy?

No prior experience is required. C# Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 3, so you can start here or from the beginning and move at your own pace.

How long does the “Custom exceptions; error design” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this C# Academy lesson?

Yes. Every C# Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. try/catch/finally, throw new vs rethrow
  2. Custom exceptions; error design
  3. IDisposable, using statement
← Back to C# Academy