C# 错误处理:try/catch 与高级技术

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

C# 错误处理:从 try/catch 到专业技术



在 C# 和 .NET 的工业级开发世界中,错误处理不仅仅是 try/catch 结构。它是一整套哲学,决定了代码的可靠性、可读性和容错性。在高级水平上,开发者不仅要捕获异常,还要合理地设计、过滤、记录异常并恢复应用程序状态。在本文中,我们将剖析 C# 错误处理的关键方面,帮助您编写更优质、更专业的代码。



1. 深入理解 try/catch/finally:资源与上下文管理



基本的 try-catch-finally 结构对每个人来说都很熟悉,但让我们从另一个角度来审视它。finally 块的主要目标是确保资源被释放,即使发生异常也是如此。在现代 C# 版本中,通常使用 using 来实现这一点,但在处理非托管资源或复杂的完成逻辑时,finally 仍然是不可或缺的。



public void ProcessFile(string path){    FileStream? fileStream = null;    try    {        fileStream = File.OpenRead(path);        // 文件处理逻辑    }    catch (FileNotFoundException ex)    {        // 特定处理:文件未找到        Log.Error($"文件 {path} 未找到:{ex.Message}");        throw; // 重新抛出异常,保留调用堆栈    }    catch (UnauthorizedAccessException)    {        Log.Warn($"无法访问文件:{path}");        // 可以执行替代操作,不重新抛出异常        return;    }    finally    {        // 确保资源释放        fileStream?.Dispose();    }}


请注意使用 throw;(不带参数)——这是关键点。与 throw ex; 不同,throw; 结构保留了原始的调用堆栈,这对调试至关重要。在实际项目中切勿使用 throw ex;,因为它会销毁原始错误发生位置的信息。



2. 自定义异常:设计领域错误模型



在大型应用程序中,标准的 .NET 异常通常不够用。创建自己的异常类可以精确地传递错误上下文,并简化上层处理。好的自定义异常应该是可序列化的,包含有意义的消息,并携带额外信息(例如,实体标识符)。



[Serializable]public class OrderProcessingException : Exception{    public int OrderId { get; }    public string FaultyStep { get; }

public OrderProcessingException(int orderId, string faultyStep, string message) : base(message) { OrderId = orderId; FaultyStep = faultyStep; }

public OrderProcessingException(int orderId, string faultyStep, string message, Exception inner) : base(message, inner) { OrderId = orderId; FaultyStep = faultyStep; }

// 用于反序列化的构造函数 protected OrderProcessingException( System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) { OrderId = info.GetInt32(nameof(OrderId)); FaultyStep = info.GetString(nameof(FaultyStep)) ?? string.Empty; }

public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { base.GetObjectData(info, context); info.AddValue(nameof(OrderId), OrderId); info.AddValue(nameof(FaultyStep), FaultyStep); }}

// 使用示例public void ValidateOrder(int orderId){ try {

博客

书籍推荐