深入理解C中的异常处理与调试技巧
立即解锁
发布时间: 2025-08-23 00:48:36 阅读量: 1 订阅数: 6 

### 深入理解 C# 中的异常处理与调试技巧
#### 1. 多异常捕获机制
在处理异常时,我们可以使用多个 `catch` 块来捕获不同类型的异常。以下是一个示例代码:
```csharp
12 }
13 catch (NullReferenceException) {
14 MessageBox.Show("NullReferenceException");
15 }
16 catch (IndexOutOfRangeException) {
17 MessageBox.Show("IndexOutOfRangeException");
18 }
19 catch (Exception) {
20 MessageBox.Show("Exception");
21 }
22 }
```
在这个示例中,`try` 块中可能会抛出三种潜在的异常,但只会执行其中一行代码,因为一旦抛出异常,就会进入异常处理程序。我们需要注释掉不想抛出异常的代码行,然后运行代码。
这里创建了一个“通用”的异常处理程序(第 19 行),用于捕获其他处理程序未捕获的任何异常。虽然不是必须这样做,但在不确定会抛出哪些异常的情况下,这是一个不错的选择。当捕获到未处理的异常时,可以向用户显示消息、记录异常或进行其他操作。
#### 2. 创建自定义异常
有时需要创建自己的自定义异常。例如,在创建一个类或组件时,可能希望抛出自定义异常。此时,需要创建一个继承自 `ApplicationException` 类的类。`ApplicationException` 类是用户应用程序抛出异常的基异常类(仅适用于非致命异常)。以下是一个创建自定义异常类的示例代码:
```csharp
1 public class UserManException : ApplicationException {
2 private string prstrSource = "UserManException";
3
4 public override string Message {
5 get { return "This exception was thrown because you . . . "; }
6 }
7
8 public override string Source {
9 get { return prstrSource; }
10
11 set { prstrSource = value; }
12 }
13 }
```
在这个示例中,重写了两个继承的属性,其他属性和方法则从基类 `ApplicationException` 类继承。这是一个非常简单的异常类,但展示了创建自定义异常类的基本方法。
#### 3. 抛出异常
如果需要抛出异常,可以使用 `throw` 语句。其格式为:
```csharp
throw expression;
```
其中,`expression` 是要抛出的异常。例如,以下代码将抛出一个新的 `IndexOutOfRangeException` 异常:
```csharp
throw new IndexOutOfRangeException();
```
需要注意的是,异常是用于处理特殊情况的,不要将其用于一般的通信目的,否则会让查看代码的人感到困惑。如果处理的是类,可以创建事件来处理与客户端的通信或使用回调。
#### 4. 处理与数据相关的异常
在处理与数据相关的异常时,遵循不将过多代码放在同一个受保护块中的原则,就可以很容易地找出是哪个与数据相关的过程或对象抛出了异常。以下是一个捕获 `SqlConnection` 类异常的示例代码:
```csharp
1 public void CatchSqlConnectionClassExceptions() {
2 SqlConnection cnnUserMan;
3
4 try {
5 // Instantiate the connection
6 cnnUserMan = new SqlConnection(STR_CONNECTION_STRING +
7 ";Connection Timeout=−1");
8 }
9 catch (ArgumentException objException) {
10 if (objException.TargetSite.Name == "SetConnectTimeout") {
11 MessageBox.Show(objException.StackTrace);
12 }
13 }
14 }
```
在这个示例中,尝试使用无效的 `Connection Timeout` 值实例化 `SqlConnection`,这显然会抛出 `ArgumentException` 异常。由于这种异常比较常见,且其他代码行也可能抛出该异常,因此还检查了是否是 `Connection Timeout` 异常(第 10 行)。
常见的数据相关异常包括:
- 连接异常,如无效的连接字符串值。
- 列中意外的空值。
- 超时异常,如查询耗时过长、服务器关闭等。
- 查询中包含无效字符,如在字符串比较中未处理撇号。
- 空结果集,导致应用程序逻辑失败。
#### 5. CLR 对异常的处理
CLR 使用受保护的代码块和异常对象来处理异常。当抛出异常时,CLR 会创建一个异常对象,并填充有关异常的信息。每个可执行文件都有一个异常信息表,每个方法在该信息表中都有一个关联的数组,该数组包含有关异常处理的信息。
异常处理过程分为两个步骤:
1. CLR 搜索数组,查找第一个保护当前执行代码行的受保护代码块,该代码块包含与异常关联的异常处理程序和过滤器。
2. 根据是否找到匹配项进行不同处理:
- 如果找到匹配项,CLR 创建描述异常的异常对象,然后执行异常抛出代码行与处理异常代码行之间的所有 `finally` 和/或 `fault` 语句。需要注意的是,异常处理程序的顺序非常重要,最内层的异常处理程序总是首先被评估。
- 如果未找到匹配项,将搜索所有调用方法,直到找到匹配项或搜索完整个调用栈。如果仍然未找到匹配项,CLR 将在转储堆栈跟踪后中止应用程序。
以下是 CLR 处理异常的流程图:
```mermaid
graph TD;
A[异常抛出] --> B[CLR 搜索数组];
B --> C{找到匹配项?};
C -- 是 --> D[创建异常对象];
D --> E[执行 finally/fault 语句];
C -- 否 --> F[搜索调用方法];
F --> G{找到匹配项?};
G -- 是 --> D;
G -- 否 --> H[中止应用程序];
```
#### 6. 使用 Debug 类
`Debug` 类位于 `System.Diagnostics` 命名空间中,可用于在开发过程中调试代码。对 `Debug` 类的方法或属性的调用不会编译到应用程序的发布版本中。
##### 6.1 启用调试
要使用 `Debug` 类,需要在使用前启用它,有以下几种方法:
- **局部启用**:在要使用 `Debug` 类的文件顶部添加以下行:
```csharp
#define DEBUG
```
- **全局启用**:
- 在命令行编译器命令中添加 `/d:DEBUG` 标志。
- 在项目属性页对话框中指定,如在构建节点的代码生成选项下选择条件编译常量项,并在文本框中添加 `DEBUG` 常量。
此外,还需要在使用 `Debug` 类的文件顶部添加以下语句:
```csharp
using System.Diagnostics;
```
##### 6.2 禁用
0
0
复制全文
相关推荐









