如果您花了任何时间编写代码,很可能您不得不处理异常处理。在Visual Studio中,当异常被抛出或最终未被处理时,调试器可以帮助您通过中断来调试这些异常,就像在遇到断点时中断一样。下面我们将讨论异常的不同分类,以及如何配置调试器何时为这些异常中断。
异常分类
我们将从调试器中异常的分类类型开始。调试器按以下方式对异常进行分类:
First Chance Exceptions:
当应用程序中首次抛出异常时,这被归类为“First Chance”异常。此时,调试器不知道应用程序是否会捕获(处理)异常。所有异常都以第一次机会异常开始。
- 每次引发异常时都会通知调试器。您可以在输出窗口和IntelliTrace中看到这些通知。
- 您可以告诉调试器要中断的首次机会异常,就像启用断点一样。
- 一旦由于首次出现异常而中断,可以通过单步执行或按“继续”继续调试。当您继续时,您的代码有机会处理此异常,如果没有,则该异常现在属于下面列出的分类之一。
User-unhandled Exceptions:
当用户代码中没有捕获(处理)第一次机会异常,并且在调用堆栈的“外部代码”中捕获时,这被归类为“用户未处理”异常。此分类仅适用于仅启用我的代码调试托管或JavaScript应用程序时。
- 默认情况下,调试器将为所有用户未处理的异常而中断。
- 一旦由于用户未处理的异常而中断,可以通过单步执行或按“继续”继续调试。异常可以在调用堆栈的“外部代码”中的某个位置处理,如果不是,则它将成为未处理的异常。
- 您可以更改默认设置,但在大多数情况下,您可能不需要更改此设置。大多数框架,比如ASP.NET,都实现了全局异常处理程序,这样应用程序就不会崩溃,但是异常并没有得到正确的处理。调试器为用户未处理的异常提供中断功能,以便在这些情况下通知您。
Unhandled Exceptions:
- 未处理的异常将使应用程序崩溃。
- 调试器将中断所有未处理的异常,以便您有机会检查导致崩溃的应用程序的状态。
- 一旦由于完全未处理的异常而中断,则无法继续调试。
配置调试器First Chance中断
要更改调试器何时中断,请转到“调试”->“窗口”->“异常设置”
当您第一次打开这个窗口时,您将看到有一个树状网格,其中有一列和复选框。
- Break When Throw,这包括调试器已知的默认异常列表,按类别分组。
注意:可能从此列表中中断的异常由正在调试的运行时确定。例如,如果您使用的是仅托管调试,则调试程序将永远不会中断C++、Win32异常等,即使它们在配置时被配置为在抛出时中断。 - 复选框。如果选中某个类别的复选框,则调试器将在调试时为所有第一次机会异常而中断。如果您不想启用所有第一次机会异常,则可以使用搜索框找到要配置的特定异常类型。
使用上下文菜单,可以显示“附加操作”列,还可以为用户未处理的异常配置行为。
- Additional Actions.只有启用“仅我的代码”时,此列才可用。用户未处理的异常仅对公共语言运行时异常和JavaScript运行时异常有意义,为其他运行时配置此异常的选项不可用,因为调试器不区分用户代码和外部代码。根据我之前的评论,您通常不想关闭此功能。如果确实要关闭此功能,可以从上下文菜单中选择“在用户代码中未处理时继续”。
此列表不是所有可能异常的详尽主列表。可以使用“添加”和“删除”来管理此默认列表中的异常。此配置随解决方案一起保存。您还可以使用search来查找具有特定关键字的所有异常,例如“null”。最后,可以使用“全部重置”将列表还原为其默认状态。
例子
- 我开始调试(F5)以运行应用程序。
- 点击“绘制半八角形”。
- 注意故障信息。
提示:当您认为有问题时,输出窗口和IntelliTrace是很好的起点。
在输出窗口中,我看到“发生了'System.NullReferenceException'类型的第一次机会异常…”如果我再次按“Draw Half octgon”,我就看不到更多的第一次机会异常发生,因此我断定此异常发生在启动路径上。
但具体发生在哪里?
- 我可以使用代码检查来寻找问题,或者逐步完成初始化逻辑。
- 相反,我将打开异常设置(Ctrl+Alt+E),并将调试器配置为针对first chance System.NullReference异常中断。
我使用搜索框查找“System.NullReferenceException”。
当抛出此异常类型时,我选中该框以断开。
提示:在“搜索”框中,可以按向下箭头选择列表中的项目,然后使用空格键切换复选框状态。
重新启动调试后,当抛出异常时,调试器会中断,我可以快速验证异常是否由空的catch块“处理”而不是真正处理,这就是导致应用程序中出现“Failure”消息的原因。
提示:如果您不熟悉特定类型的异常,异常助手可以为您提供有用的信息。注意,我也可以从这里通过使用“抛出此异常类型时中断”复选框来配置异常设置。
因为我在第一次机会异常时被打断了,所以我可以转到Locals窗口,在那里我可以看到“m_halfocagon”的值为空。看看代码,我发现变量从未初始化过。
然后我重新启动调试并观察我的应用程序是否成功运行。