我能否通过编程启用/禁用异常中断?

13
我希望能够在调试时像Visual Studio 2008的菜单Debug/Exception Dialog中一样,在异常出现时中断程序...但是我的程序在我希望调试的部分之前,可能会有许多有效的异常。
因此,是否可能使用#pragma或其他方法自动地启用和禁用它,而只在特定的代码段中发生?

我不认为你能够做到,但我也不能确定。 - Greg D
1
你的程序有很多有效的异常?这是什么意思? - Dan Tao
1
这意味着我正在使用使用异常来报告代码中的条件的库。它们只是警告而不是致命错误,并且是API的一部分,所以我不能停止它们,而是必须适当地捕获并编写相应的代码。 - AnthonyLambert
5个回答

9
唯一接近此功能的方法是在你的方法上放置DebuggerNonUserCodeAttribute属性。
这将确保标记方法中的任何异常不会导致调试器中断。
这里有一个很好的解释:链接...
这是一种属性,用于告诉调试器:“与我无关。这不是我的代码!”轻信的调试器将相信你,并不会在该方法中中断:使用该属性使调试器完全跳过该方法,即使您正在逐步执行代码;在方法内捕获的异常不会中断进入调试器。它会将其视为对框架程序集的调用,并且如果出现未处理的异常,则会在调用该方法的代码中报告一级调用堆栈。
代码示例:
public class Foo
{
    [DebuggerNonUserCode]
    public void MethodThatThrowsException()
    {
        ...
    {
}

3
关于条件断点呢?如果我理解正确,你可以设置断点仅在特定变量或表达式的值为真时触发。

1

将你的 try catch 块包裹在 #if DEBUG 中

    public void Foo()
    {
        #if DEBUG
        try
        #endif
        {
            //Code goes here
        }
        #if DEBUG
        catch (Exception e)
        {
            //Execption code here
        }
        #endif
    }

我喜欢将大括号放在#if之外,因为这样可以在调试内部或外部时保持代码处于同一范围。

如果您仍想要异常处理但需要更多详细信息,您可以这样做

        try
        {
            //code
        }
        catch (FileNotFoundException e)
        {
            //Normal Code here
            #if DEBUG
            //More Detail here
            #endif
        }
        #if DEBUG
        catch (Exception e)
        {
            //handel other exceptions here
        }
        #endif

使用类似这样的方式看起来更加简洁: [Conditional("Debug")] private void MyMethod() { ... } - Nate Zaugg

1

这对你来说可能有点晚了,但这是我经常试图教人们保守使用异常的最大原因。只有在发生灾难性事件且无法合理继续时才使用异常。

调试程序时,我经常打开“第一次机会异常”(调试 -> 异常)来调试应用程序。如果有很多异常发生,很难找到哪里出了“问题”。

此外,它会导致一些反模式,如臭名昭著的“catch throw”,并混淆真正的问题。有关更多信息,请参见我在博客文章中提到的内容。

就你的问题而言,你可以仅针对特定类型的异常打开第一次机会调试。除非其他异常属于相同类型,否则这应该能很好地解决问题。


我建议您实现警告异常和致命异常,按函数分组,只能打开/关闭您想要捕获的异常。我认为异常不应仅仅被使用,而是正确地使用!我的问题是我没有编写生成异常的所有代码,它们在任何地方都使用通用异常,因此很难区分。 - AnthonyLambert

0
你也可以使用断言(asserts)代替断点(breakpoints)。例如,如果你只想在第二次调用该函数时,在循环的第5次迭代上设置断点,你可以这样做:
bool breakLoop = false;

...
    Work(); // Will not break on 5th iteration.
    breakLoop = true;
    Work(); // Will break on 5th iteration.
...

public void Work() {
    for(int i=0 ; i < 10 ; i++) {
        Debug.Assert (!(breakLoop && i == 5));
        ...
    }
}

所以在第一次调用 Work 时,当 breakLoop 是 false 时,循环将会运行而不会断言,第二次经过循环时将会中断。


1
您也可以使用常规断点上的命中计数特性来完成此操作,而无需编写代码。 - Jeremy
是的,对于我所演示的内容,只有一半是正确的,但我试图演示使用配置变量以及条件来确定何时触发断言的一般原则。 - Mark Booth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接