====== 代码调试与错误处理 ======
本章节主要讲解如何在开发过程中发现代码逻辑错误(调试),以及如何防止程序因运行时错误而崩溃(异常处理)。
===== 代码调试 (Debugging) =====
代码调试是程序员的核心技能之一。它允许开发者让程序在特定的位置暂停,一步一步地执行代码,并实时查看内存中变量的变化。
==== 1. 断点 (Breakpoints) ====
**定义**: 断点是标记在代码行上的一个“红点”,告诉编译器程序运行到这里必须暂停(挂起)。
* **设置/取消断点**:
* **鼠标操作**: 在代码编辑区左侧的灰色竖条(行号左边)点击。
* **快捷键**: 光标停留在某一行,按下 **F9**。
* **作用**: 程序运行到断点处会停止,进入“调试模式”。
==== 2. 调试控制快捷键 ====
当程序在断点处暂停后,使用以下快捷键控制程序的执行流:
^ 快捷键 ^ 名称 ^ 作用详解 ^
| **F10** | 逐过程 (Step Over) | **跳过当前方法的内部细节**。如果当前行是一个函数调用(例如 `GetMax()`),按下 F10 会直接执行完整个函数,停在下一行代码。适用于你确定该函数没问题,只想看后续结果时。 |
| **F11** | 逐语句 (Step Into) | **进入代码细节**。如果当前行是一个函数调用,按下 F11 会跳转到该函数的定义内部,从函数的第一行开始执行。适用于你想检查该函数内部逻辑时。 |
| **Shift + F11** | 跳出 (Step Out) | 执行完当前函数的剩余代码,并返回到调用该函数的地方。 |
| **F5** | 继续 (Continue) | 结束单步调试,直接运行程序,直到遇到下一个断点或程序结束。 |
==== 3. 变量监控 (Variable Monitoring) ====
在调试模式下(程序暂停时),查看变量值的几种方式:
- **鼠标悬停 (Hover)**: 将鼠标光标移动到变量名上,会弹出一个小窗口显示当前该变量的值。
- **局部变量窗口 (Locals)**: IDE 底部通常会自动显示当前作用域内所有变量的值。
- **监视窗口 (Watch)**: 可以手动输入想要监控的变量名或表达式(例如 `i + 5`),实时查看计算结果。
- **即时窗口 (Immediate)**: 可以在其中输入代码并立即执行,用于临时测试某个逻辑。
===== 代码的错误处理 (Error Handling) =====
在程序运行过程中,可能会出现不可预知的错误(如用户输入非数字字符、文件不存在、网络断开等)。如果不处理,程序会直接崩溃(闪退)。C# 使用 `try-catch` 机制来捕获和处理这些异常。
==== 1. try-catch 基础结构 ====
try
{
// 可能会出现异常的代码
// 例如:类型转换、文件读取、数据库连接
int a = int.Parse("abc"); // 这里会报错
}
catch (Exception ex) // 捕获异常
{
// 当 try 中的代码报错时,会跳转到这里执行
// 这里通常用于记录日志、提示用户,而不是让程序崩溃
Console.WriteLine("程序出错了:" + ex.Message);
}
==== 2. 实战案例:循环判断直到输入正确 ====
这是一个非常经典的用法。当需要用户输入整数时,如果用户输入了字母,`int.Parse` 会抛出异常。利用 `try-catch` 配合循环,可以强制用户一直输入,直到格式正确为止。
**逻辑分析**:
- 使用 `bool` 变量作为循环的开关。
- 在 `try` 块中进行转换,如果成功,将开关设为 `true`(退出循环)。
- 如果失败,进入 `catch` 块,提示错误,开关保持 `false`(继续循环)。
static void Main(string[] args)
{
int aegg = 0; // 用于存储最终合法的年龄
// 初始化循环条件:kar 为 false 时一直循环
// 也可以写成 while (kar == false) 或 while (!kar)
for (bool kar = false; kar == false; )
{
try
{
Console.WriteLine("请输入年龄:");
// 尝试将用户输入的字符串转换为整数
// 如果用户输入 "abc",这里会抛出异常,直接跳到 catch 块
aegg = int.Parse(Console.ReadLine());
Console.WriteLine("输入成功,年龄为: " + aegg);
// 如果代码能执行到这一行,说明上面没有报错
kar = true; // 修改循环条件,准备退出循环
}
catch
{
// 只有当 try 中出现错误时才会执行这里
Console.WriteLine("输入错误!请输入纯数字,请重试。");
// kar 依然是 false,循环将继续
}
}
Console.WriteLine("程序继续执行...");
}
==== 3. 最佳实践补充 (TryParse) ====
虽然 `try-catch` 可以处理格式错误,但在 C# 中,专门用于数值转换的场景推荐使用 `TryParse` 方法,因为它性能更高且代码更简洁(不需要抛出异常)。
// 进阶写法:使用 TryParse
int age;
Console.WriteLine("请输入年龄:");
// TryParse 返回 bool 值表示成功或失败,转换后的值放入 out 参数 age 中
while (!int.TryParse(Console.ReadLine(), out age))
{
Console.WriteLine("输入错误,请输入纯数字:");
}
Console.WriteLine("年龄是:" + age);