C# 异常处理完全指南:try-catch-finally、异常类型、自定义异常与最佳实践
异常是程序执行期间出现的问题。C# 异常是对程序运行时异常情况的响应(如除零)。异常提供从程序一部分向另一部分转移控制的方式。C# 异常处理基于四个关键字:try、catch、finally、throw。
关键字说明
- try:标识可能激活特定异常的代码块,后跟一个或多个 catch 块。
- catch:在想处理问题的地方捕获异常,
catch关键字指示捕获。 - finally:无论是否抛出异常都执行的语句块。如打开文件,必须关闭无论是否异常。
- throw:问题出现时抛出异常,使用
throw关键字。
语法结构
try {
// 可能引发异常的语句
} catch (ExceptionName e1) {
// 错误处理代码
} catch (ExceptionName e2) {
// 错误处理代码
} catch (ExceptionName eN) {
// 错误处理代码
} finally {
// 无论是否异常都执行的语句
}
可列出多个 catch 捕获不同异常类型。
C# 异常类层次
C# 异常由类表示,直接或间接派生自 System.Exception。主要派生分支:
System.ApplicationException:应用程序生成的异常基类,程序员自定义异常应从此派生System.SystemException:所有预定义系统异常的基类
常见系统异常类
| 序号 | 异常类及说明 |
|---|---|
| 1 | System.IO.IOException:处理 I/O 错误 |
| 2 | System.IndexOutOfRangeException:数组索引越界 |
| 3 | System.ArrayTypeMismatchException:数组类型不匹配 |
| 4 | System.NullReferenceException:引用空对象 |
| 5 | System.DivideByZeroException:除零错误 |
| 6 | System.InvalidCastException:类型转换错误 |
| 7 | System.OutOfMemoryException:内存不足 |
| 8 | System.StackOverflowException:栈溢出 |
异常处理示例:除零处理
using System;
namespace ErrorHandlingApplication {
class DivNumbers {
int result;
DivNumbers() { result = 0; }
public void division(int num1, int num2) {
try {
result = num1 / num2;
} catch (DivideByZeroException e) {
Console.WriteLine("Exception caught: {0}", e);
} finally {
Console.WriteLine("Result: {0}", result);
}
}
static void Main(string[] args) {
DivNumbers d = new DivNumbers();
d.division(25, 0);
Console.ReadKey();
}
}
}
输出:
Exception caught: System.DivideByZeroException: Attempted to divide by zero.
Result: 0
自定义异常
用户定义异常类派生自 Exception 类:
using System;
namespace UserDefinedException {
public class TempIsZeroException : Exception {
public TempIsZeroException(string message) : base(message) { }
}
public class Temperature {
int temperature = 0;
public void showTemp() {
if (temperature == 0) {
throw new TempIsZeroException("Zero Temperature found");
} else {
Console.WriteLine("Temperature: {0}", temperature);
}
}
}
class TestTemperature {
static void Main(string[] args) {
Temperature temp = new Temperature();
try {
temp.showTemp();
} catch (TempIsZeroException e) {
Console.WriteLine("TempIsZeroException: {0}", e.Message);
}
Console.ReadKey();
}
}
}
输出:TempIsZeroException: Zero Temperature found
重新抛出异常
在 catch 块中用 throw; 重新抛出当前异常(保留堆栈跟踪),或 throw new OtherException("msg", e); 包装异常:
try { ... }
catch (Exception e) {
// 记录日志
Log.Error(e);
// 重新抛出原异常
throw;
// 或包装为新异常
// throw new BusinessException("Operation failed", e);
}
异常处理最佳实践
- 仅捕获可处理的异常:不要捕获
Exception基类,除非顶层日志记录 - 使用 finally 释放资源:或用
using语句(实现IDisposable) - 避免用异常控制业务流程:异常开销大,预判条件用
if - 提供有意义的错误消息:包含上下文信息便于诊断
- 保留堆栈跟踪:用
throw;而非throw e; - 实现全局异常处理:ASP.NET Core 用
UseExceptionHandler,WPF/WinForms 用DispatcherUnhandledException - 遵循异常命名约定:以
Exception结尾,提供三个构造函数
标准异常构造函数模式
public class MyException : Exception {
public MyException() { }
public MyException(string message) : base(message) { }
public MyException(string message, Exception inner) : base(message, inner) { }
protected MyException(SerializationInfo info, StreamingContext context) : base(info, context) { }
}
C语言
- PLC与DCS:如何选择合适的自动化系统
- Liebherr PHS Allround:模块化托盘搬运系统 支撑大产能柔性生产
- Liebherr 扩展托盘搬运系统 助力柔性生产
- HS Flex 搬运系统提升 Hermle C42 加工中心操作效率与存储
- 掌握 C# using 指令:命名空间导入、别名与静态导入全解析
- C语言文件处理完全指南:fopen、fprintf、fread 与 fseek
- C++ 异常处理实战:try、catch、throw 完整指南与示例
- 掌握 C++ 信号处理:安全中断管理与优雅程序终止
- 精通 Python 异常处理:try、except、else 与 finally 详解
- 精通 Python 异常处理:try、except、finally 与 raise 高效用法
- 精通 Java 异常处理:try-catch、finally、throw 与 throws 详解
- Java 9 模块系统:链接时、自定义运行时镜像与实战