【问题标题】:Visual Studio 2015+ C#/.NET Debugger: How to break only on unhandld exceptions?Visual Studio 2015+ C#/.NET 调试器:如何仅在未处理的异常上中断?
【发布时间】:2017-01-07 23:36:01
【问题描述】:

所以,我找到了很多关于这个确切主题的资源和 StackOverflow 问题,但它似乎只适用于相当老的 Visual Studi0 版本——比如 2012。

我的问题是我希望调试器仅在未处理异常时才中断。官方 MSDN 表示,调试器会在所谓的“第一次机会”异常上中断,这意味着即使要处理异常,它的预期功能也会中断。

我发现让调试器在我包装在 try-catch 中的 InvalidCastException 上中断非常烦人。有什么方法可以强制调试器忽略将要处理的第一次机会异常?一个常见的答案是禁用特定 CLR 异常类型的中断,但这确实是一个荒谬的解决方案。我不想到处压制异常。我只是不想在我已经提防异常时被通知抛出异常。

【问题讨论】:

  • 旁注:我强烈建议使用其他一些不使用异常作为流控制的库。没有理由在 C# 中引发 InvalidCastException(is 比抛出异常快得多)。
  • 我同意isas 是处理打字的更好方法。我引用的InvalidCastException 更像是通过 LINQ 扩展使用 .Cast() 。一个更好、更通用的例子是NullReferenceException

标签: c# .net visual-studio debugging visual-studio-2015


【解决方案1】:

我可以想象您的挫败感,但您的 VisualStudio 设置肯定有些奇怪。我可以向您保证,在我的设置中,VS 永远不会捕获已处理的异常,并且在从 VS2008 到 VS2015 的所有 VS 版本中都是如此。

您在输出窗口中看到的“FirstChance 异常”行是一条信息,表明在触发任何处理程序或堆栈解除之前的那个时刻刚刚引发了异常。

但这并不意味着 VisualStudio 有任何中断。仅向调试输出写入一行代码,程序继续运行 - 堆栈展开,执行最近匹配的 catch,程序向前运行。

现在,VS/Debugger/CLR 可以在抛出异常时中断,但必须打开它。您可以通过 Debug->Windows->Exceptions 或按 CTRL+D+E 到达那里。当您单击它时,应该会出现一个新面板,其中包含一个例外列表以及每个例外的一个或两个选项:

  • 投掷时断裂
  • 在未处理时中断

但这可能会因您的 VS 版本而异。例如,在 VS Community 2015 中,只有“投掷时中断”,“未处理”是不可见的,但仍然对所有这些都有效。您只是无法关闭“未处理”的中断。

无论如何,重要的是默认情况下,所有“未处理”都被选中,而“抛出时”则没有或几乎没有。在 VS2015Community 中,我看到默认设置了以下“抛出时”:

  • 一些 C++“Platform::xxxx”异常
  • System.Reflection.MissingMetadata [
  • System.Reflection.MissingRuntimeArtifact [
  • System.Windows.Markup.XamlParseException [
  • Javascript 异常:拒绝访问,代码 0x80070005
  • 一些 ManagedDebuggingAssistants:LoaderLock、ContextSwitch...
  • 一些 Win32 异常

仅此而已。也许总共有 10..20 种非常具体的类型,我没有数过。在“Common Language Runtime”组中,默认情况下只有 三个 被选中,即上面列出的那些。没有 InvalidCastExceptions。

如果您的 VS 在它被抛出的那一刻触发,那么这意味着您或有权访问您的 VS 的人对其进行了不同的配置。最有可能的是,在那个“ExceptionSettings”面板中,您将“InvalidCastException”标记为“抛出时中断”。去那里,查看“InvalidCastExceptions”复选框的状态并取消选中它,然后重试。

如果这对 InvalidCastExceptions 的情况有所帮助,并且如果此问题也发生在某些其他异常上,那么您可以对任何其他类型重复此操作您不想在抛出时中断 .是的,这意味着您(或其他人)在某个时间点点击了那里并检查了它们以破坏它们。

如果您将其中的许多都勾选为break-on-throw,那么您可以点击子树根并选中/取消选中整个组,而不是点击每一个。 (顺便说一句。也许你在一周或一个月前不小心点击并检查了整个组?)

此外,还有一个非常有用的“Restore Defaults”(恢复默认值),甚至还有一个名为“Restore the list to default settings”的按钮,这两个按钮都只是将所有内容重置为默认设置(就像我在上面写的列表中一样:一些 C++,一些反射,一些 win32 等等)。

最后,无论您在 ExceptionSettings 面板中 取消选择 break-on-thrown 的任何异常,VisualStudio 仍将中断任何未处理的异常。 (除非您看到另一组标记为“未处理”的复选框 - 即 VS2010Pro 中有这样的东西,但在 VS2015Community 中我看不到它......也许它是 Pro 的东西)

【讨论】:

  • 感谢您的详细回答。相反,我认为我的问题可能与如何处理 Windows Store App 中的异常有关。任何时候未处理的异常都会一直抛出到App.g.csDebugger.Break()。从那里,有一个带有异常消息的变量e。沿着堆栈向下移动以查看真正的罪犯可能会很棘手。
  • @NickAlexander: aaahhh app.g.cs...这个是自动生成的.. phuf.. 听起来.. 不吉利
  • @NickAlexander:但是!如果我没记错的话,app.g.cs 只会在 app.xaml 更改时更新——请尝试打开 app.g.cs 文件,编辑它,即注释掉“debugger.Break()` 行,然后构建 (重建,不要调用'CLEAN'阶段)应用程序。你甚至不需要启动 - 检查'BUILD'是否导致app.g.cs被恢复。这条线很有可能将保持注释掉
  • @quequetzalcoatl 直到现在我才真正意识到这可能是 Windows Store App 运行时环境而不是 Visual Studio 的“问题”。 Break when throw 有助于解决这个问题,但就像我说的,有时它可能会很麻烦。我不知道解决方案可能是什么,但如果有一种比遍历堆栈搜索更快的方法来识别罪犯,那就太好了。我相信您是正确的,最外面的异常实际上是 UnhandledException 并且 InnerException 将具有真正的异常。 App.g.cs 是自动生成的。
【解决方案2】:

从 Visual Studio 2015 开始,您可以转到调试 -> Windows -> 异常设置。您可以根据具体情况定义要自动中断的异常。当 VS 因异常而中断时,还有一个指向此窗口的链接 - 点击窗口底部的“异常设置”。

在我的家用计算机上,我只看到一列“Thrown”,所以就您而言,没有办法只抛出未处理的异常。不过,在工作中,我有一个名为“未处理的用户”的第二列,它可以让我完全按照您所说的去做。选中“用户未处理”并取消选中“抛出”会导致它仅在未处理的异常上中断,而不是在捕获的异常上中断。我想这可能是 Visual Studio 专业版的一个功能——我在家里使用社区版。

【讨论】:

  • 感谢您的回复。这是我看到的解决方案推荐的确切内容,但是在任何地方(工作、家庭等)的任何 VS 安装中,我都没有看到“用户未处理”列。取消选中“Thrown”列有助于解决一些例外情况,但这仍然不是一个完美的解决方案。特别是在 Windows 应用商店应用程序中,未处理的异常一直抛出到 App.g.cs 中的 Debugger.Break。有时试图解开堆栈可能真的很烦人。
【解决方案3】:

如果你使用像VS2015这样的更高版本的VS,它没有像旧VS版本那样启用/禁用Unhandled Exception的选项,但它有自己的特点:

因此,如果我们只想捕获未处理的异常,我们可以禁用该复选框。

有什么方法可以强制调试器忽略将要处理的第一次机会异常?

我不想到处压制异常。我只是不想在我已经提防异常时被通知抛出异常。

但是,如果您仍想获得将要处理的第一个更改异常消息,则对于此问题没有好的解决方法,因为此时调试器不知道该异常是否会被应用程序捕获(处理) ,如果启用该复选框,它将捕获第一次机会异常(当应用程序首次抛出异常时,这被归类为“第一次机会”异常)。

参考:

https://blogs.msdn.microsoft.com/visualstudioalm/2015/02/23/the-new-exception-settings-window-in-visual-studio-2015/

https://blogs.msdn.microsoft.com/visualstudioalm/2015/01/07/understanding-exceptions-while-debugging-with-visual-studio/#unhandled.

【讨论】:

    【解决方案4】:

    请记住,您可以在 Release 或 Debug 旁边定义自己的构建配置,这些配置可以遵循代码中的 #if <name>#endif 标记。例如,您可以在此处根据配置决定是否要关注异常。

    【讨论】:

      猜你喜欢
      • 2017-01-27
      • 2023-03-26
      • 1970-01-01
      • 1970-01-01
      • 2015-06-22
      • 2010-09-12
      • 2011-12-02
      • 1970-01-01
      相关资源
      最近更新 更多