You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何区分自定义抛出的.NET异常与第三方或运行时异常?

区分.NET异常来源的可行方案

你提到的需求完全合理——区分手动抛出、依赖库抛出和意外运行时异常,有助于更精准地处理错误,并非过度纠结于最佳实践。以下是几种不用大量字符串解析的可行方案:

方案一:优化你的泛型异常思路

你设计的AppException<T>思路是可行的,可进一步完善以贴合.NET异常设计规范:

public abstract class AppException : Exception
{
    protected AppException(string message, Exception innerException) 
        : base(message, innerException) { }
}

public class AppException<T> : AppException where T : Exception, new()
{
    public AppException() : this(null, null) { }
    public AppException(string message) : this(message, null) { }
    public AppException(string message, Exception innerException) 
        : base(message, innerException ?? new T()) { }
}

使用时,手动抛出的异常会被包裹在自定义的AppException<T>中,捕获时可精准区分:

// 手动抛出
throw new AppException<ArgumentException>("输入参数无效");

// 捕获区分
try
{
    DoTheThing(inputInt);
}
catch (AppException<ArgumentException> ex)
{
    // 处理自己抛出的参数异常
}
catch (AppException ex)
{
    // 处理其他自定义包装的异常
}
catch (ArgumentException ex)
{
    // 处理依赖库或意外抛出的参数异常
}
catch (Exception ex)
{
    // 处理其他未预期异常
}

这种方式既遵循了使用预定义异常的最佳实践,又通过自定义包装类明确标记了异常来源。

方案二:利用Exception的Data属性标记来源

无需自定义异常类型,直接在手动抛出预定义异常时,通过Data字典添加来源标记:

// 手动抛出时添加标记
var ex = new ArgumentException("输入无效");
ex.Data["SourceType"] = "Manual";
throw ex;

捕获时通过检查Data属性区分:

try
{
    DoTheThing(inputInt);
}
catch (ArgumentException ex)
{
    if (ex.Data.Contains("SourceType") && ex.Data["SourceType"].ToString() == "Manual")
    {
        // 处理自己手动抛出的参数异常
    }
    else
    {
        // 处理依赖库或意外抛出的参数异常
    }
}

这种方式完全使用预定义异常,无需自定义类型,缺点是Data为弱类型,需要统一标记规则。

方案三:自定义异常基类+预定义异常作为内部异常

创建自定义的ManualException基类,将预定义异常作为内部异常抛出:

public class ManualException : Exception
{
    public ManualException(Exception innerException) : base(innerException.Message, innerException) { }
    public ManualException(string message, Exception innerException) : base(message, innerException) { }
}

使用时:

// 手动抛出时,将预定义异常作为内部异常
throw new ManualException("输入无效", new ArgumentException());

捕获时:

try
{
    DoTheThing(inputInt);
}
catch (ManualException ex) when (ex.InnerException is ArgumentException)
{
    // 处理自己抛出的参数异常
}
catch (ManualException ex)
{
    // 处理其他手动抛出的异常
}
catch (ArgumentException ex)
{
    // 处理依赖库或意外的参数异常
}

这种方式既保留了预定义异常的类型信息,又通过自定义基类明确了是手动抛出的异常。

总结

  • 你的泛型异常思路合理,优化后可很好满足需求;
  • 若不想自定义类型,Data属性是轻量方案;
  • 自定义基类+内部异常的方式兼顾了类型安全和来源区分;
  • 区分异常来源是合理需求,并非过度纠结最佳实践——最佳实践核心是合理使用异常类型,而非完全禁止自定义异常来标记来源。

内容的提问来源于stack exchange,提问作者David

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 03:34:53