news 2026/8/11 1:42:29

csharp自定义异常与异常设计建议

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
csharp自定义异常与异常设计建议

1.何时需要自定义异常?

在以下情况下,应该创建自定义异常:

1.业务逻辑错误

标准异常无法准确描述业务错误。需要特定的错误信息和处理逻辑。示例:账户余额不足、订单状态无效等。

2.需要额外的错误信息

标准异常无法提供足够的上下文信息。需要添加自定义属性来存储额外信息。示例:验证失败时需要显示哪些字段有问题。

3.需要特定的异常处理

调用者需要根据异常类型采取不同的处理措施。标准异常类型不够具体。示例:网络错误vs业务错误需要不同的处理。

4.API设计

公开的API需要明确的异常类型。让调用者能够清楚地知道可能发生的错误。示例:库或框架提供的异常类型。

2.创建自定义异常类

自定义异常类必须继承自Exception或其子类

基本结构

C#
public classCustomException : Exception
{
public CustomException() :base()
{
}
public CustomException(string message): base(message)
{
}
public CustomException(string message, Exception innerException)
:base(message, innerException)
{
}
}

C#
/// <summary>
///
表示余额不足时抛出的异常。
/// 包含当前余额和所需金额信息,便于调用方处理。
/// </summary>
public class InsufficientBalanceException : Exception
{
/// <summary>
/// 获取当前账户余额。
/// </summary>
public decimal CurrentBalance { get; }

/// <summary>
/// 获取操作所需的金额。
/// </summary>
public decimal RequiredAmount { get; }

/// <summary>
/// 初始化异常实例,使用当前余额和所需金额构造错误消息。
/// </summary>
/// <param name="currentBalance">当前余额</param>
/// <param name="requiredAmount">所需金额</param>
public InsufficientBalanceException(decimal currentBalance, decimal requiredAmount)
: base($"余额不足。当前余额:{currentBalance},需要:{requiredAmount}")
{
CurrentBalance = currentBalance;
RequiredAmount = requiredAmount;
}

/// <summary>
/// 初始化异常实例,并指定内部异常。
/// </summary>
/// <param name="currentBalance">当前余额</param>
/// <param name="requiredAmount">所需金额</param>
/// <param name="innerException">导致当前异常的原始异常</param>
public InsufficientBalanceException(decimal currentBalance, decimal requiredAmount, Exception innerException)
: base($"余额不足。当前余额:{currentBalance},需要:{requiredAmount}", innerException)
{
CurrentBalance = currentBalance;
RequiredAmount = requiredAmount;
}
}

使用示例

C#
void Withdraw(decimal amount)
{
if (balance < amount){
throw new InsufficientBalanceException(balance, amount);
}
balance-= amount;
}

3.异常命名规范

自定义异常类应该遵循命名规范:

命名规则:类名以Exception结尾。使用描述性的名称,清楚地表达异常的含义。使用 PascalCase 命名。

说明:命名应该清楚地表达异常的含义,让调用者能够理解发生了什么错误。

4.异常设计原则

1.可序列化

如果异常需要在不同进程或机器间传递,应该标记为可序列化。

使用[Serializable]特性。

2.提供有意义的错误消息

错误消息应该清楚地说明发生了什么错误。包含足够的上下文信息。

3.添加自定义属性

如果需要额外的错误信息,添加自定义属性。属性应该是只读的,避免修改。

4.提供多个构造函数

提供无参构造函数。提供带消息的构造函数。提供带消息和内部异常的构造函数。

5.实现序列化支

如果标记为可序列化,需要实现序列化构造函数。实现GetobjectData方法。

5.完整示例:可序列化异常

C#
using System;
using System.Runtime.Serialization;

[Serializable]
public class ValidationException : Exception
{
/// <summary>
///
获取无效的字段名称数组。
/// </summary>
public string[] InvalidFields { get; }

/// <summary>
/// 初始化异常实例,指定无效字段列表。
/// </summary>
/// <param name="invalidFields">无效字段名称数组</param>
public ValidationException(string[] invalidFields)
: base($"验证失败。无效字段:{string.Join(",", invalidFields)}")
{
InvalidFields = invalidFields;
}

/// <summary>
/// 初始化异常实例,指定无效字段列表和内部异常。
/// <summary>
/// <param name="invalidFields">无效字段名称数组</param>
/// <param name="innerException">内部异常</param>
public ValidationException(string[] invalidFields, Exception innerException)
: base($"验证失败。无效字段:{string.Join(",", invalidFields)}", innerException)
{
InvalidFields = invalidFields;
}

/// <summary>
/// 序列化构造函数(用于反序列化)。
/// </summary>
/// <param name="info">序列化信息</param>
/// <param name="context">流上下文</param>
protected ValidationException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
InvalidFields = (string[])info.GetValue(nameof(InvalidFields), typeof(string[]));
}

/// <summary>
/// 自定义序列化数据,将 InvalidFields 添加到序列化信息中。
/// </summary>
/// <param name="info">序列化信息</param>
/// <param name="context">流上下文</param>
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue(nameof(InvalidFields), InvalidFields);
}
}

6.异常使用建议

何时使用自定义异常?

业务逻辑错误,标准异常无法准确描述。

需要额外的错误信息。

需要特定的异常处理逻辑。

公开的API需要明确的异常类型。

何时使用标准异常?

参数验证错误:使用 ArgumentException、ArgumentNullException。

对象状态错误:使用InvalidOperationException。

空引用错误:使用NullReferenceException(通常由运行时抛出)。

索引越界:使用IndexOutOfRangeException(通常由运行时抛出)。

选择建议

优先使用标准异常,除非有特殊需求。

自定义异常应该表示特定的业务错误。

避免创建过多的自定义异常类型。

7.异常设计最佳实践

1.保持简单

异常类应该简单,只包含必要的属性和方法。避免在异常类中添加复杂的业务逻辑。

2.提供足够的上下文

错误消息应该包含足够的上下文信息。添加自定义属性存储额外的错误信息。

3.文档化异常

使用XML注释文档化异常。说明异常的使用场景和触发条件。

4.避免过度使用

不要为每个错误都创建自定义异常。优先使用标准异常,除非有特殊需求。

5.考虑异常层次结构

如果多个异常有共同特征,可以创建基类异常。使用继承来组织异常类型。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/11 1:39:40

2024学术写作工具全测评:从文献管理到格式优化

1. 论文写作工具现状与痛点分析本科阶段的论文写作往往伴随着大量文献查阅、格式调整和重复性劳动。根据2023年教育技术调查报告显示&#xff0c;83%的本科生在论文撰写过程中遇到过以下典型问题&#xff1a;文献管理混乱&#xff1a;手动整理参考文献耗时且易出错格式调整痛苦…

作者头像 李华
网站建设 2026/8/11 1:35:30

旁挂负载分担组网场景_分析报告

旁挂负载分担组网场景 — 技术分析报告 HCIE级别综合实验 | 交换机旁挂防火墙负载均衡组网方案全解析 目录 方案概述与需求分析网络拓扑架构接入层设计&#xff1a;MSTP VRRP 二层高可用汇聚层设计&#xff1a;OSPF VRF 路由规划路由策略与流量工程防火墙旁挂与双机热备VRR…

作者头像 李华
网站建设 2026/8/11 1:33:44

基于STM32与LoRa的物联网环境检测系统:从硬件选型到低功耗设计

在实际的单片机毕业设计项目中&#xff0c;一个集成了多种无线通信技术的环境检测系统是检验学生综合能力的典型课题。将STM32作为主控核心&#xff0c;结合LoRa进行远距离、低功耗的数据采集&#xff0c;通过WiFi将数据上传至云端或本地服务器&#xff0c;并利用GPS获取设备的…

作者头像 李华
网站建设 2026/8/11 1:32:43

类似WorkBuddy的企业Agent有哪些?主流办公AI Agent选型与深度对比

随着大语言模型从“单次问答”向“自主规划与执行”演进&#xff0c;AI Agent&#xff08;智能体&#xff09;已成为企业和个人提升生产力的核心工具。在众多产品中&#xff0c;WorkBuddy 凭借其独特的“多专家团队协作”和“一人公司&#xff08;OPC&#xff09;”模式吸引了广…

作者头像 李华