当它被抛出和捕获时,不要在那个异常处停止调试器

Posted

技术标签:

【中文标题】当它被抛出和捕获时,不要在那个异常处停止调试器【英文标题】:Don't stop debugger at THAT exception when it's thrown and caught 【发布时间】:2010-11-28 01:39:57 【问题描述】:

在工具/异常中,我设置了在抛出异常时调试器停止的选项。不管是不是被抓到。

如何排除该规则的例外情况?在我的代码中某处有一个捕获的异常,它是程序逻辑的一部分。所以我显然不希望该异常在每次被命中时都停止调试器。

示例:我想忽略第 344 行的 nullreference 异常(已捕获)。我想停止所有其他例外情况

【问题讨论】:

当这个异常是你的编程逻辑的一部分时(想想,如果你真的必须这样实现它)——那么它至少应该是一个自己创建的、派生的异常。这样你就可以应用布赖恩的解决方案了。 这里有问题:***.com/questions/1957907/… @tanascius - +1 我同意在大多数情况下例外不是做出合乎逻辑的决定的最佳方式;但是在某些情况下,例如反序列化处理异常有时是不可避免的,因此 throw>catch>handle 是唯一合理的选择。 @Ando 对不起我的错。一次审核多个标签很有效,但并不总是准确的。 @tanascius:您可能仍然需要捕获一个已知的框架异常,然后才能抛出自己的异常作为响应。您的建议并不总是可行的。 【参考方案1】:

DebuggerHidden是你的朋友!

公共语言运行时不为该属性附加任何语义。它供源代码调试器使用。例如,Visual Studio 2005 调试器不会在使用此属性标记的方法中停止,并且不允许在该方法中设置断点。 Visual Studio 2005 调试器识别的其他调试器属性是 DebuggerNonUserCodeAttribute 和 DebuggerStepThroughAttribute。

在 VS2010 上测试,效果很好。

虽然DebuggerStepThrough 似乎也适用于某些特定的调试器版本,但DebuggerHidden 似乎适用于基于这两个答案的 cmets 的更广泛的情况。

请注意,这两个选项目前不适用于iterator block methods 或async/await methods。这可以在以后的 Visual Studio 更新中修复。

注意,.NET Core + Rider 的组合不支持,可以vote the issue.

【讨论】:

在 VS2008 上工作。您必须将其应用于整个方法,包括 catch 块,否则您将在其他地方中断 我将该属性添加到一个方法中,而调试器只是停止了它的调用方法。我错过了什么吗? 应该是这样的。为避免这种情况,您必须处理异常...或者也将调用者方法标记为DebuggerHidden... 请注意,DebuggerStepThrough 属性应该足以避免异常中断。 DebuggerHidden 的作用类似于 DebuggerNonUserCode 和 DebuggerStepThrough 属性的组合。 可悲的是,这个doesn't work if the method in question is an iterator method :/【参考方案2】:

如果我没记错的话,您可以在包含您不希望触发异常的代码的方法上使用 DebuggerStepThrough 属性。我想您可以隔离在方法中触发烦人异常的代码并用属性装饰它。

【讨论】:

从 malinger 的回答和我的经验来看,这个答案似乎是不正确的。 DebuggerStepThrough 属性不会影响调试器在出现首次机会异常时的行为。 @Tim,我测试过,它不会停止。查看我的答案:***.com/questions/1420390/3455100#3455100 +1 在 VS2010 中适用于纯 .NET 4.0 和 Silverlight 4 代码,适用于未处理的异常。 重要提示:这不适用于 async-await 类型的方法。更多here 根据 MSDN,DebuggerStepThrough 属性对 CLR 没有意义。它由调试器解释。似乎在各种情况下都不能可靠工作,DebuggerHidden 会可靠工作***.com/a/3455100/141172【参考方案3】:

DebuggerStepThrough 是用于防止调试器中断存在 try/catch 的方法。

但只有在 Visual Studio 的调试选项(菜单工具/选项、节点调试/常规)的常规设置中未取消选中“仅启用我的代码(仅限托管)”选项时它才有效...

有关该属性的更多信息http://abhijitjana.net/2010/09/22/tips-on-debugging-using-debuggerstepthrough-attribute/

DebuggerHidden 只会阻止 Debugger 显示引发异常的方法。相反,它将显示堆栈上未标记该属性的第一个方法...

【讨论】:

请注意,这在 VS 2015 中默认不再有效,see the VS blog for how to enable it 遗憾的是,VS 2015 的解决方法不适用于 VS 2019。【参考方案4】:

在 Visual Studio 2015 中默认情况下,其他答案中指定的属性(以及其他答案,例如 DebuggerNonUserCode 属性)不再以相同的方式工作。调试器将在具有这些属性的方法市场中中断异常,这与在旧版本的 VS。要关闭改变其行为的性能增强,您需要更改注册表设置:

reg add HKCU\Software\Microsoft\VisualStudio\14.0_Config\Debugger\Engine /v AlwaysEnableExceptionCallbacksOutsideMyCode /t REG_DWORD /d 1

更多信息请访问visual studio blog。

(这可能应该是对最佳答案的评论,但我没有足够的代表)

【讨论】:

【参考方案5】:

您无法在代码中的特定位置找出引发的异常。但是,您可以禁用特定类型的异常。

如果您自己的代码抛出有问题的异常,我会将其设为自定义异常,派生自任何合适的类型,然后禁用此派生类型的调试中断。

将系统异常禁用为 NullReferenceException 会影响整个系统,这在开发过程中当然是不可取的。

请注意,异常有两种中断行为:

抛出:如果选中,则在抛出此类异常时立即中断 用户未处理:如果选中,则仅当此类异常未由 try/catch 处理时才中断。

您可以删除“抛出”中对 NullReferenceException 的检查,这将使您在每次系统通过代码中的相关行时不会中断,但如果您在其他代码中发生一些未处理的 NullReference 预期仍会中断系统的一部分。

【讨论】:

向 Visual Studio 2010 中的方法添加 DebuggerStepThrough 属性将防止调试器停止该方法引发的未处理异常。 我测试过,并没有阻止;它仍然停止 @Shimmy - 为我工作!确保将 DebuggerStepThrough 应用于每个方法,从引发它的点到您希望异常在调用堆栈中可见的点。如果您捕获异常并在所有方法都用 DebuggerStepThrough 修饰的调用层次结构中处理它,那么您将永远不会看到 VS 在该异常上中断。【参考方案6】:

所以我找到了一个适用于 VS 2019 的解决方案,它比我想要的要复杂一些,但对于我的用例来说,有必要解决这个问题。

说明

首先将导致问题的代码移到它自己的函数中,这样您就不会抑制周围代码中的异常,并用 DebuggerStepThrough 属性标记它(或者 DebuggerHidden 也可以)。

[DebuggerStepThrough]
public void ExceptionThrowingFunction()

    //.. Code that throws exception here

那就这样称呼吧

OutsourceException(ExceptionThrowingFunction);

然后选择一个单独的项目(模块),您不关心抑制其中的所有异常,或者专门为此目的创建。重要的是这是一个单独的项目,以便您的主项目仍然可以在此异常类型上中断。就我而言,我已经有一个名为 SharedFunctions 的小型实用程序项目,所以我把它放在那里。代码相当稳定,大部分时间不需要调试。

在一个名为 ExceptionUtils 的类中,我添加了以下函数:

public static T OutsourceException<T>(Func<T> func)

    T result = default;
    try
    
        result = func.Invoke();
    
    catch  
    return result;


public static T OutsourceException<T, Y>(Func<T, Y> func, Y arg)

    T result = default;
    try
    
        result = func.Invoke(arg);
    
    catch  
    return result;


public static void OutsourceException<T>(Action<T> action, T arg)

    try
    
        action.Invoke(arg);
    
    catch  

您可能需要添加更多这些,这些仅涵盖您的函数中有 0-1 个参数的基本情况。

最后,当你运行代码时,它仍然会在 Outsource 函数中出现异常,并显示如下消息: 如果您选中底部的复选框(在本例中为“SharedFunctions.dll”),它将添加一条规则,即如果从该程序集中抛出异常,则应忽略该异常。一旦检查了这一点,就应该抑制异常。这种类型的主程序集中的所有其他异常仍将正常中断。

这里发生了什么?

由于 VS 2015 中的更改破坏了 [DebuggerHidden] 和类似属性(请参阅此处另一个答案中链接的 blog post),这些属性现在将异常传递给调用类,而调试器只是在那里中断。如果我们将调用类移动到另一个程序集中,我们可以使用exception conditions system 抑制异常。

为什么不直接修复异常?

某些异常无法从代码中完全删除,例如当您尝试在 UWP 应用程序中访问 Package.Current 时。它总是会在调试器中抛出异常,这只能由微软解决。在这种情况下,另一种解决方案是用#if !DEBUG 将其包围,但在其他情况下这并不实用。

【讨论】:

以上是关于当它被抛出和捕获时,不要在那个异常处停止调试器的主要内容,如果未能解决你的问题,请参考以下文章

IndexOutOfBoundsException 没有被抛出 JFrame

调试的时候没有在断点处停止的原因

XCTAssertThrows 在断点处停止

异常的抛出和捕获

远程调试不会在断点处停止

颤振调试器不会在断点处停止