ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

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

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///表示余额不足时抛出的异常。/// 包含当前余额和所需金额信息便于调用方处理。/// /summarypublic class InsufficientBalanceException : Exception{/// summary/// 获取当前账户余额。/// /summarypublic decimal CurrentBalance { get; }/// summary/// 获取操作所需的金额。/// /summarypublic decimal RequiredAmount { get; }/// summary/// 初始化异常实例使用当前余额和所需金额构造错误消息。/// /summary/// param namecurrentBalance当前余额/param/// param namerequiredAmount所需金额/parampublic InsufficientBalanceException(decimal currentBalance, decimal requiredAmount): base($余额不足。当前余额:{currentBalance}需要:{requiredAmount}){CurrentBalance currentBalance;RequiredAmount requiredAmount;}/// summary/// 初始化异常实例并指定内部异常。/// /summary/// param namecurrentBalance当前余额/param/// param namerequiredAmount所需金额/param/// param nameinnerException导致当前异常的原始异常/parampublic 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///获取无效的字段名称数组。/// /summarypublic string[] InvalidFields { get; }/// summary/// 初始化异常实例指定无效字段列表。/// /summary/// param nameinvalidFields无效字段名称数组/parampublic ValidationException(string[] invalidFields): base($验证失败。无效字段:{string.Join(,, invalidFields)}){InvalidFields invalidFields;}/// summary/// 初始化异常实例指定无效字段列表和内部异常。/// summary/// param nameinvalidFields无效字段名称数组/param/// param nameinnerException内部异常/parampublic ValidationException(string[] invalidFields, Exception innerException): base($验证失败。无效字段:{string.Join(,, invalidFields)}, innerException){InvalidFields invalidFields;}/// summary/// 序列化构造函数用于反序列化。/// /summary/// param nameinfo序列化信息/param/// param namecontext流上下文/paramprotected ValidationException(SerializationInfo info, StreamingContext context): base(info, context){InvalidFields (string[])info.GetValue(nameof(InvalidFields), typeof(string[]));}/// summary/// 自定义序列化数据将 InvalidFields 添加到序列化信息中。/// /summary/// param nameinfo序列化信息/param/// param namecontext流上下文/parampublic 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.考虑异常层次结构如果多个异常有共同特征可以创建基类异常。使用继承来组织异常类型。
返回列表