跳转到内容

C Sharp 异常处理策略

来自代码酷

C#异常处理策略[编辑 | 编辑源代码]

异常处理是C#编程中确保程序健壮性和可靠性的核心机制。本指南将系统讲解C#异常处理的最佳实践,涵盖基础概念到高级策略,并提供实际应用案例。

1. 异常处理基础[编辑 | 编辑源代码]

异常(Exception)是程序运行时发生的意外情况,可能由以下原因导致:

  • 无效的用户输入
  • 文件/网络资源不可用
  • 内存不足
  • 编程逻辑错误

C#使用try-catch-finally结构处理异常:

try {
    // 可能抛出异常的代码
    int.Parse("abc"); // 格式错误
}
catch (FormatException ex) {
    Console.WriteLine($"输入格式错误: {ex.Message}");
}
finally {
    Console.WriteLine("清理资源执行区");
}

输出:

输入格式错误: Input string was not in a correct format.
清理资源执行区

2. 异常类型层次[编辑 | 编辑源代码]

classDiagram class Object class Exception { +string Message +string StackTrace +Exception InnerException } Object <|-- Exception Exception <|-- SystemException Exception <|-- ApplicationException SystemException <|-- ArgumentException SystemException <|-- NullReferenceException SystemException <|-- IndexOutOfRangeException

关键异常类型:

  • System.Exception:所有异常的基类
  • System.SystemException:CLR抛出的系统级异常
  • System.ApplicationException:用户自定义异常的基类(不推荐继承)

3. 最佳实践策略[编辑 | 编辑源代码]

3.1 精确捕获异常[编辑 | 编辑源代码]

避免捕获基类Exception,应捕获具体异常类型:

// 不推荐
try { /* 代码 */ } 
catch (Exception ex) { /* 处理所有异常 */ }

// 推荐做法
try {
    File.ReadAllText("missing.txt");
}
catch (FileNotFoundException ex) {
    Console.WriteLine("文件未找到,请检查路径");
}
catch (IOException ex) {
    Console.WriteLine("IO错误: " + ex.Message);
}

3.2 异常筛选器(C# 6+)[编辑 | 编辑源代码]

使用when关键字添加条件判断:

try {
    ConnectToDatabase();
}
catch (SqlException ex) when (ex.Number == 1205) {
    // 处理死锁特定错误
    RetryOperation();
}
catch (SqlException ex) {
    LogError(ex);
    throw; // 重新抛出
}

3.3 资源清理模式[编辑 | 编辑源代码]

使用using语句自动释放IDisposable资源:

using (var stream = new FileStream("data.txt", FileMode.Open))
{
    // 使用stream对象
} // 自动调用Dispose()

等效于:

FileStream stream = null;
try {
    stream = new FileStream("data.txt", FileMode.Open);
    // 使用stream
}
finally {
    stream?.Dispose();
}

4. 自定义异常[编辑 | 编辑源代码]

创建自定义异常应继承自Exception类:

public class InventoryException : Exception
{
    public int ItemId { get; }
    
    public InventoryException(int itemId, string message) 
        : base(message) => ItemId = itemId;
}

// 使用示例
try {
    if (stockCount <= 0)
        throw new InventoryException(123, "库存不足");
}
catch (InventoryException ex) {
    Console.WriteLine($"商品{ex.ItemId}异常: {ex.Message}");
}

5. 性能考量[编辑 | 编辑源代码]

异常处理开销较大,应避免:

  • 使用异常控制正常流程
  • 在频繁调用的代码中捕获异常

优化方案:

// 使用Try模式替代异常
if (int.TryParse(input, out var number)) {
    // 成功处理
}
else {
    // 处理无效输入
}

6. 实际案例:Web API异常处理[编辑 | 编辑源代码]

ASP.NET Core中的全局异常处理:

// 自定义异常中间件
public class ExceptionMiddleware
{
    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        try {
            await next(context);
        }
        catch (ValidationException ex) {
            context.Response.StatusCode = 400;
            await context.Response.WriteAsJsonAsync(new {
                Error = "验证失败",
                Details = ex.Errors
            });
        }
        catch (Exception ex) {
            // 记录日志
            Log.Error(ex, "全局异常");
            
            context.Response.StatusCode = 500;
            await context.Response.WriteAsJsonAsync(new {
                Error = "系统错误",
                RequestId = context.TraceIdentifier
            });
        }
    }
}

7. 异常处理数学建模[编辑 | 编辑源代码]

异常处理概率模型: P(系统稳定)=1i=1nP(异常i)×(1P(处理成功i)) 其中:

  • P(异常i):第i类异常发生概率
  • P(处理成功i):对该异常的成功处理概率

总结[编辑 | 编辑源代码]

异常处理策略对照表
场景 推荐做法 避免做法
using语句/Dispose模式 | 依赖finalizer
Try模式(如TryParse) | 使用异常控制流程
记录日志后终止 | 静默吞没异常
包装自定义异常 | 暴露底层异常细节

遵循这些策略可显著提高代码的健壮性和可维护性。记住:异常处理的目标不是消除所有异常,而是确保程序在异常情况下能优雅降级或安全终止。