简介:C# Windows窗体应用程序中的错误处理
在"从零开始的C#应用"系列的第25课中,Tim Corey专注于一个关键但常常被误解的话题:C# Windows Forms应用中的错误处理。 Tim解释说,错误处理不仅仅是到处抛出try-catch块,而是关于有意设计应用程序如何响应无效输入、意外情况和用户错误。
在本课中,Tim 将通过先前系列中构建的锦标赛查看器表单,逐步讲解实际案例。 通过观察错误是如何发生的以及应该如何处理它们,我们能更深入地、实际地理解何时让应用程序失败,何时停止执行,以及何时通过有意义的反馈引导用户。 让我们一步一步详细查看Tim在视频中的解释。
理解问题:未处理的异常
在课程开始时,Tim 介绍了目标:在现有的 Tournament Viewer 表单中添加基础的错误处理。 他立即展示了一个真实的问题——当两个队伍得到相同的分数并点击"Score"按钮时,应用程序抛出异常。
Tim解释说,虽然此行为在Visual Studio中可见,但对于终端用户来说,情况更糟。 如果应用程序以.exe格式运行,错误消息将出现,然后在关闭消息框后应用程序将崩溃。 Tim强调,这对于面向用户的应用程序来说是不可接受的行为。
为什么使用笼统的try-catch块是个坏主意
接着,Tim 讨论了开发者常犯的一个错误:把整个方法包裹在try-catch块中,并称其为"错误处理"。他强烈批评这种做法,称其更像是"错误吞食"而非真正的处理。
在这个时候,Tim 解释了一个重要的理念:如果一个应用程序以意想不到的方式失败,那么它应该以一种惊人的方式失败。 悄悄隐藏错误会使调试变得更困难,并会导致状态损坏传播。 只有在错误是用户预期并导致时才应该拦截。
在UI层中针对性的Try-Catch
与其包裹所有内容,Tim 介绍了如何仅在可能失败的代码行周围应用 try-catch 块。 他演示了如何使用try块包围评分逻辑,并使用命名变量捕获Exception。
Tim强调了两个最佳实践:
务必为异常变量命名,以便于访问其详细信息。
切勿使用throw ex重新抛出异常; 因为它会破坏重要的堆栈跟踪信息。 相反,使用 throw; 如果需要重新抛出。
在这种情况下,由于错误发生在UI中,Tim选择直接在此通过显示一个包含异常消息的MessageBox来处理。
使用MessageBox改善用户反馈
Tim添加了一个MessageBox.Show调用,用于向用户显示清晰的错误信息。 当再次输入平分比分时,应用程序现在显示:
应用程序出现以下错误:我们不允许此应用程序中出现并列。
Tim指出,这已经是一个很大的改进。 错误已处理,数据库未更新,应用程序继续安全运行。
永远不要信任用户:输入验证
Tim的一项核心原则在这里明确重复: 永远不要信任用户。
在此阶段,应用程序假定用户将输入有效的数字分数。 Tim解释了为什么这种做法是危险的,并介绍了在尝试处理用户输入之前验证它的想法。
他创建了一个名为IsValidData的私有方法,该方法检查:
- 两个分数输入是否都是有效数字
是否两者分数都为零
分数是否相同
最初,此方法返回一个bool值,允许调用代码停止执行并显示通用错误信息。
从布尔验证到描述性错误
Tim对这种"您需要输入有效数据"的通用信息不满意。 他解释说,良好的错误处理应该准确告知用户出错的地方。
为改进这一点,他将验证方法改为返回字符串而不是布尔值。 空字符串表示没有错误。 否则,该字符串包含特定信息,例如:
"Score 1 value is not a valid number"
"您没有为任何一支队伍输入分数"
"我们不允许在此应用程序中有平局"
这使得UI可以显示有针对性且有意义的信息,而不是模糊的警告。
使用 Else-If 链解决逻辑错误
测试后,Tim注意到一个逻辑缺陷:无效的数字输入有时会触发"不允许平局"消息。 他解释了为什么会发生这种情况——解析数字失败会将数值设置为零,而单独的if语句允许后续条件覆盖之前的信息。
为了解决这个问题,Tim将验证检查转换为else-if链。 这确保一旦满足一个错误条件,其余的都将被跳过。 Tim解释说,这样可以使逻辑更清晰、更安全,并且更易于维护。
错误处理不仅仅是Try-Catch
Tim退后一步,并澄清了一个关键结论: 错误处理并不总是意味着使用try-catch块。
手动验证(在处理之前检查用户输入)同样重要。 通过及早验证,应用程序可以防止不良数据进入数据库或业务逻辑。
他还解释道,并不是所有事情都需要验证。 像下拉菜单和列表框这样的封闭系统已经限制了输入。 但是,自由文本字段必须始终进行验证。
错误处理应该在哪里进行
在课程的结尾,Tim 解答了一个常见问题:错误处理应该放在哪里?
他的经验法则:
验证应存在于整个应用程序中,包括后端。
通常应在前端捕获异常,因为这是可以通知用户的地方。
Tim指出,只有当系统能够恢复时,进行后端异常处理才有意义——例如,当SQL不可用时,可以从SQL数据库切换到文本文件。
关于错误处理的最终思考
Tim最后总结道,良好的错误处理可以提高应用程序的稳定性、用户体验和长期可维护性。 他警告不要使用通用的try-catch块,并鼓励开发者有意识地考虑验证和异常流。
本课程为构建具有弹性的Windows Forms应用程序奠定基础——这些应用程序能够引导用户、保护数据,并在必要时安全失败。

