18

不管其他可能达到相同结果的选项(即手动添加断点),是否可以以编程方式将断点添加到 Visual Studio 项目的源代码中?

如:

try
{
    FunctionThatThrowsErrors(obj InscrutableParameters);
}
catch(Exception ex)
{
    Log.LogTheError(ex);
    AddBreakPointToCallingFunction();
}

这样当你下次在调试中运行时,它会自动在上次运行期间引起问题的所有点设置断点。

我并不是说这是一种特别有用的调试方式。我只是想知道是否有能力。

4

5 回答 5

46

你可以打电话System.Diagnostics.Debugger.Break()

您还可以告诉 Visual Studio 中断所有异常,甚至是已处理的异常,方法是转到菜单Debug->Exceptions...并检查Thrown当前仅选中“用户未处理”的所有位置。

于 2009-05-08T21:06:52.403 回答
40

你启发了我去探索这个——感谢你让我整夜保持清醒。:) 这是您可以做到的一种方法。

Visual Studio 有非常好的断点支持。更酷的功能之一是您可以告诉它在断点被命中时运行 Visual Studio 宏。这些宏可以完全访问开发环境,即它们可以执行您可以在键盘上手动执行的任何操作,包括设置其他断点。

该解决方案是 1) 在程序中放置一个顶级 try/catch 以捕获所有异常,2) 在运行宏的 catch 块中放置一个断点,以及 3) 让宏查看异常以找出在哪里它来自,并在那里放置了一个断点。当您在调试器中运行它并发生异常时,您将在有问题的代码行处有一个新断点。

拿这个示例程序:

using System;

namespace ExceptionCallstack
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                func1();
            }
            catch (Exception e)
            {
                Console.WriteLine("Oops");
                Console.ReadKey();
            }
        }

        static void func1()
        {
            func2();
        }

        static void func2()
        {
            func3();
        }

        static void func3()
        {
            throw new Exception("Boom!");
        }
    }
}

目标是throw当您在调试器中运行 func3 并得到错误时,以编程方式在 func3 中设置断点。为此,首先创建一个新的 Visual Studio 宏(我调用了我的 SetBreakpointOnException)。将此粘贴到新模块 MyDebuggerMacros 或其他任何内容中:

Imports System
Imports EnvDTE
Imports EnvDTE80
Imports EnvDTE90
Imports System.Diagnostics
Imports System.Text.RegularExpressions

Public Module DebuggerMacros

    Sub SetBreakpointOnException()

        Dim output As String = ""

        Dim stackTrace As String = DTE.Debugger.GetExpression("e.StackTrace").Value
        stackTrace = stackTrace.Trim(New Char() {""""c})
        Dim stackFrames As String() = Regex.Split(stackTrace, "\\r\\n")

        Dim r As New Regex("^\s+at .* in (?<file>.+):line (?<line>\d+)$", RegexOptions.Multiline)
        Dim match As Match = r.Match(stackFrames(0))
        Dim file As String = match.Groups("file").Value
        Dim line As Integer = Integer.Parse(match.Groups("line").Value)

        DTE.Debugger.Breakpoints.Add("", file, line)

    End Sub

End Module

一旦这个宏就位,回到catch块并用 F9 设置一个断点。然后右键单击红色断点圆圈并选择“When Hit...”。在结果对话框的底部,有一个选项告诉它运行宏 - 下拉列表并选择您的宏。现在,当您的应用程序抛出未处理的异常时,您应该获得新的断点。

关于这一点的注意事项和警告:

  • 不是正则表达式大师,我相信其他人可以做出更好的东西。
  • 这不处理嵌套异常(InnerException 属性)——如果你愿意,你可以反对它。:) 检查 GetExpression("e.InnerException") 和递归,也许。
  • 它对 excpetion 的 StackTrace 字符串进行文本解析,而不是更复杂的对象图分析(深入研究 Exception.TargetSite 并使用反射)。通常的警告适用于这种方法的脆弱性。
  • 出于某种原因,它似乎将断点放入了某个“备用空间”。初始调试会话结束后,您将看不到代码中的新断点。但是如果你在调试器中再次运行程序,它就在那里,并且像“禁用所有断点”这样的东西会影响它。如果有人想找到一种方法来清理它,那么了解正在发生的事情会很好。也许在 .suo 文件中挖掘?

希望这可以帮助!

于 2009-05-09T11:07:30.103 回答
4

它并没有真正响应您的问题,但您可以根据您使用Debug.Assert设置的条件导致调试器中断。因此,与其说“下次我运行导致异常的函数,请中断”,您可以在函数中添加断言以在条件不应该时中断。毕竟,不能保证一个函数仅仅因为上次抛出异常就抛出异常。:)

于 2009-05-08T21:12:06.120 回答
2

我认为您不能真正“添加断点”,但是您可以通过调用 System.Diagnostics.Debugger.Break() 指示调试器暂停执行,以便检查出了什么问题

于 2009-05-08T21:09:09.823 回答
0

此外,Visual Basic 有一个名为 Stop 的关键字,它本质上将充当断点和中断执行。

于 2010-05-25T15:56:45.520 回答