一次性捕获:如何在C#中捕获多个异常而不重复代码
\n\n想象一下:您正在编写一个处理文件、网络和数据库的应用程序。在一个方法中,可能会抛出FileNotFoundException、IOException或UnauthorizedAccessException。传统方法是使用三个catch块,内部包含相同的代码。这违反了DRY(不要重复自己)原则,并使代码变成“意大利面条”。
好消息是:在C#中有几种优雅的方法可以一次性捕获多个异常。在本教程中,我们将从基础到高级逐一介绍所有方案,您将学习如何编写干净、可维护的错误处理代码。
\n\n为什么这很重要?真实场景
\n\n假设您正在开发一个用于备份的控制台应用程序。它读取文件、压缩文件并将其发送到远程服务器。在每个阶段都可能发生不同的异常:
\n\n- \n
- 读取文件:
FileNotFoundException、PathTooLongException\n - 压缩:
OutOfMemoryException\n - 发送:
HttpRequestException、TimeoutException\n
如果您为每个异常编写单独的catch块并包含相同的日志记录代码,代码将变得臃肿。如果以后需要更改逻辑,则必须在三个地方进行修改。这正是学会一次捕获多个异常的价值所在。
方法1. 经典方法:多个catch块(C# 6之前)
\n\n最简单直接的方法是连续编写多个catch块。C#会根据异常类型自动选择相应的块:
try\n{\n // 可能抛出不同异常的代码\n string content = File.ReadAllText(@"C:\\data\\config.txt");\n int value = int.Parse(content);\n await SendToServerAsync(value);\n}\ncatch (FileNotFoundException ex)\n{\n Console.WriteLine($"文件未找到:{ex.Message}");\n LogError(ex);\n}\ncatch (FormatException ex)\n{\n Console.WriteLine($"数据格式无效:{ex.Message}");\n LogError(ex);\n}\ncatch (HttpRequestException ex)\n{\n Console.WriteLine($"网络错误:{ex.Message}");\n LogError(ex);\n}\n\n优点:清晰易懂,可以针对每个异常进行不同处理。
\n缺点:如果操作相同,则会导致代码重复。
方法2. 在单个catch中捕获多个异常(C# 6+)
\n\n从C# 6开始,您可以在一个catch块中使用|列出多个异常类型。这减少了重复并保持了可读性:
try\n{\n // 有风险的代码\n}\ncatch (FileNotFoundException | FormatException | HttpRequestException ex)\n{\n Console.WriteLine($"发生错误:{ex.Message}");\n LogError(ex);\n // 对所有三种类型通用的额外逻辑\n}\n\n重要提示:所有异常在层次结构上必须兼容。例如,不能混合IOException和NullReferenceException——它们除了Exception之外没有共同的基类。但在C# 6+中这是允许的,编译器会将变量ex转换为通用基类型。
何时使用这种方法?
\n- \n
- 当所有异常的处理逻辑相同时。 \n
- 当您希望避免嵌套的
if或switch块时。 \n - 在需要简洁性的小方法中。 \n
方法3. 异常过滤器(C# 6+)
\n\n异常过滤器是一种强大的机制,允许您使用when关键字根据条件捕获异常。您可以捕获同一个异常,但根据其属性采用不同的逻辑:
try\n{