显示页面讨论反向链接回到顶部 本页面只读。您可以查看源文件,但不能更改它。如果您觉得这是系统错误,请联系管理员。 ====== C# 中的 throw 关键字详解 ====== 在 C# 编程中,`throw` 关键字用于显式地引发异常。它不仅用于报告错误,还在控制程序流程和异常传播中扮演关键角色。 ===== 1. 基础用法 ===== 最基本的形式是抛出一个继承自 `System.Exception` 的对象实例。 <code csharp> public void ValidateUser(string name) { if (name == null) { // 基础用法:实例化并抛出 throw new ArgumentNullException(nameof(name), "用户名不能为空"); } } </code> **注意**:一旦 `throw` 语句执行,当前方法的后续代码将不再运行,控制权将转交给调用堆栈中最近的 `catch` 块。 ===== 2. 重新抛出异常 (Rethrowing) ===== 这是 C# 开发中**最容易出错**的地方。当你在 `catch` 块中捕获异常并希望将其传递给上层调用者时,有两种写法,但结果截然不同。 ==== 2.1 正确的做法:throw; ==== 使用不带参数的 `throw;` 可以保留原始异常的堆栈跟踪(Stack Trace)。 <code csharp> try { ProcessData(); } catch (Exception ex) { Log(ex); // ✅ 正确:保留原始堆栈信息,就像错误是在 ProcessData 内部发生的一样 throw; } </code> ==== 2.2 错误的做法:throw ex; ==== 如果你抛出了捕获的异常变量(`throw ex;`),堆栈跟踪会被重置。 <code csharp> try { ProcessData(); } catch (Exception ex) { Log(ex); // ❌ 错误:堆栈跟踪被重置,看起来错误好像是发生在这行代码,而不是 ProcessData 内部 throw ex; } </code> ===== 3. throw 表达式 (C# 7.0+) ===== 从 C# 7.0 开始,`throw` 不仅仅是一个语句,还可以作为一个**表达式**使用。这意味着你可以在赋值、条件运算符(三元运算符)或 Lambda 表达式中直接使用它。 ==== 3.1 在空合并运算符中 ==== 这是最常见的用法,用于简化参数验证。 <code csharp> public class Person { public string Name { get; } public Person(string name) { // 如果 name 为 null,直接抛出异常,否则赋值 Name = name ?? throw new ArgumentNullException(nameof(name)); } } </code> ==== 3.2 在三元运算符中 ==== <code csharp> string GetGrade(int score) { return (score >= 0 && score <= 100) ? (score >= 60 ? "Pass" : "Fail") : throw new ArgumentOutOfRangeException(nameof(score), "分数必须在0到100之间"); } </code> ==== 3.3 在 Lambda 表达式主体中 ==== <code csharp> Func<string, string> cleaner = s => s ?? throw new Exception("字符串不能为null"); </code> ===== 4. 常见异常类型 ===== 在 C# 中使用 `throw` 时,应尽量抛出 .NET 框架提供的标准异常,而不是通用的 `Exception`。 ^ 异常类型 ^ 适用场景 ^ | **ArgumentNullException** | 参数值为 null,但该方法不允许 null。 | | **ArgumentOutOfRangeException** | 参数值超出了允许的范围(例如索引越界)。 | | **ArgumentException** | 参数无效,但不属于上述两种情况。 | | **InvalidOperationException** | 当对象处于不适合执行该方法的状态时(例如在连接关闭时尝试读取数据库)。 | | **NotImplementedException** | 方法尚未实现(通常用于开发阶段)。 | ===== 5. 最佳实践总结 ===== - **保留堆栈**:在 `catch` 块中重新抛出时,永远使用 `throw;` 而不是 `throw ex;`。 - **利用 nameof**:在抛出参数相关异常时,使用 `nameof(parameterName)` 来获取参数名,这样重构代码时参数名会自动更新。 * `throw new ArgumentNullException(nameof(id));` - **不要通过异常控制逻辑**:异常应该用于“异常”情况,不要用 `throw` 来做普通的流程跳转(例如跳出循环),这会严重影响性能。 - **自定义异常**:如果标准异常无法准确描述错误,可以创建继承自 `Exception` 的自定义类。 登录 Detach Close 该主题尚不存在 您访问的页面并不存在。如果允许,您可以使用创建该页面按钮来创建它。 csharp/系统关键字/throw.txt 最后更改: 2025/12/02 15:12由 张叶安 登录