0Pricing
C# Academy · 课时

自定义异常与错误设计

创建小型自定义异常,选择正确的内置类型(ArgumentException、InvalidOperationException),并通过 InnerException 添加上下文信息。

自定义异常与错误设计 是 CoddyKit 上的免费 C# Academy 课时。 这是第 2 节课,共 3 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C# Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C# Academy 课程共包含 3 节课。

目的与目标

目标:让错误清晰且便于捕获。

  • 针对具体失败使用具体类型
  • 使用良好的消息和 InnerException 提供上下文
  • 适用时优先使用内置类型

自定义异常类型

从 Exception 派生,将名称以 Exception 结尾,并添加标准构造函数。携带少量有用的数据。

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 提供上下文

使用领域异常包装底层异常,并将 InnerException 设置为底层异常,以保留根本原因。

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);
    }
  }
}

优先选择内置类型

对于常见问题,请使用内置类型:ArgumentNullException、ArgumentOutOfRangeException、FormatException、InvalidOperationException 等。

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); }
  }
}

异常与防护检查

在异常情况下使用异常。对于预期的失败,优先使用 TryX 防护检查或返回代码。

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");
  }
}

错误设计检查清单

检查清单:

  • 可能时选择内置类型。
  • 否则,创建带有标准构造函数的小型 CustomException。
  • 附加 InnerException 以保留根本原因。
  • 对意外情况使用异常;对预期失败使用 TryX。

自定义异常设计

快速检查:在 C# 中,自定义异常类型推荐采用什么设计?

总结

总结:优先使用内置异常;否则,定义带有标准构造函数的小型自定义类型,并使用 InnerException 添加上下文,同时不丢失根本原因。

常见问题解答

「自定义异常与错误设计」课时是免费的吗?

是的 — 「自定义异常与错误设计」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C# Academy 课程的其余内容,请升级到 CoddyKit PRO。 C# Academy 课程共包含 3 节课。

「自定义异常与错误设计」这节课中我会学到什么?

创建小型自定义异常,选择正确的内置类型(ArgumentException、InvalidOperationException),并通过 InnerException 添加上下文信息。 你通过在浏览器中直接运行的动手代码来练习 C# Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C# Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C# Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 3 节。

「自定义异常与错误设计」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C# Academy 课中编写并运行代码吗?

能。每节 C# Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. try/catch/finally、throw new 与重新抛出
  2. 自定义异常与错误设计
  3. IDisposable 与 using 语句
← 返回 C# Academy