你启发了我去探索这个——感谢你让我整夜保持清醒。:) 这是您可以做到的一种方法。
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 文件中挖掘?
希望这可以帮助!