Visual Studio调试器 .NET技巧和诀窍

70

我多年来一直在使用VS的调试器,但偶尔会发现一个以前从未注意到的功能,并想:“该死!我怎么会错过它呢?它太有用了!”

[免责声明:这些技巧适用于C#项目的VS 2005版本,在旧版本的VS或其他语言中不保证可用]

跟踪对象实例

正在使用给定类的多个实例?如何区分它们? 在垃圾回收之前的编程时代,很容易跟踪引用-只需查看内存地址。在.NET中,你不能这样做-对象可能会移动。 幸运的是,监视视图可以让你右键单击监视并选择“创建对象ID”。

这将在实例的值后附加{1#}、{2#}等,有效地为实例赋予了唯一的标签。

标签将在该对象的生命周期内保留。

监视变量的有意义的值

默认情况下,监视变量的值是其类型。如果要查看其字段,必须展开它,如果字段很多或者它们执行一些复杂操作,这可能需要很长时间(甚至超时!)。

然而,一些预定义的类型显示了更有意义的信息:

  • 字符串显示它们的实际内容
  • 列表和字典会显示它们的元素计数等。

如果我的自定义类型也能这样该多好啊?

嗯...

...通过.NET反编译器进行一些质量时间,就可以轻松完成这个任务,只需要在我的自定义类型上使用DebuggerDisplay属性即可:

[System.Diagnostics.DebuggerDisplay("Employee: '{Name}'")]
public class Employee {
    public string Name { get { ... } }
    ...
}

重新运行,它可以正常工作。

关于这个主题,这里有更多的信息:MSDN

在所有异常处中断

...即使是在代码中被处理过的异常! 我知道,我是个萌新,竟然没有从出生以来就知道这个,但是无论如何,这里还是有帮助到别人的可能性:

您可以强制调试过程在每次抛出异常时都进入调试模式。 您是否曾经进行了几个小时的错误查找,最终发现了像这样的代码段?

try {
    runStrangeContraption();
} catch(Exception ex) {
    /* TODO: Will handle this error later */
}

在这些情况下捕获所有异常真的很方便。
可以通过 调试 > 异常... (Ctrl-Alt-E) 启用此功能。选中每种需要的异常类型的 '抛出' 列中的框。


那些对我来说是一些令人头痛的时刻。
你想分享你的吗?


这更像是一个备忘录式的帖子,而不是一个问题,但也许其他人会发现它有用。希望我自己也能学到一些新东西。 - Cristian Diaconescu
可能是"Visual Studio .NET调试器的"隐藏秘密"?的重复问题。 - Roger Pate
14个回答

19
try {
    // do something big
}
catch {
    // breakpoint set here:
    throw CantHappenException("something horrible happened that should never happen.");
}

如何查看最初引发的异常?在观察窗口中输入 $exception。


1
真的吗?太棒了!这非常有用。特别是当你在处理一份写得很糟糕的项目时。 - EightyOne Unite

17

我学到了另一个很棒的技巧:

System.Diagnostics.Debugger.Break()

以编程方式使调试器在下一条指令处中断。非常棒的是,这也适用于在Release模式下编译的程序,而不需要调试信息。


7
我倾向于将其用 If (System.Diagnostics.Debugger.IsAttached) { System.Diagnostics.Debugger.Break() } 包围起来。 否则客户端在未移除该代码时可能会收到严重错误! - Gavin Miller

12

我总是确保在创建新线程时设置“Name”属性。这样,在调试时,我可以更轻松地识别不同的线程。


9

7

两个代码技巧:

我非常喜欢System.Diagnostics.DebuggerStepThrough属性; 你可以将其附加到类、方法或属性上,在调试时默认情况下不进入代码。我更喜欢它而不是DebuggerHidden属性,因为如果确实需要调试被忽略的代码,则仍然允许您在其中设置断点。

另一个(有时)有用的调用是System.Diagnostics.Debugger.Launch(); 当执行到它时,你将会看到“选择调试器”对话框,并启动调试器。这有点粗鲁,但对于特别难以附加到进程的情况非常有用,比如由另一个进程生成并立即执行你的代码的进程。


2
我最近了解到了System.Diagnostics.DebuggerStepThrough - 很有用。 同时,在过去的几周中,我经常使用Debugger.Launch - 对于一个特定的项目,如果我尝试直接从“附加到进程”对话框中附加,该进程就会死亡,但是使用Debugger.Launch()可以很好地附加(同样的?!)调试器。 - Cristian Diaconescu

7

6
在即时窗口中输入.load sos :)

1
什么是解释?互联网上有很多页面解释如何使用SOS。 - leppie

4
我发现模块窗口在很多时候都非常有用。它可以告诉你调试器是否已经加载了所需的dll文件以及加载的dll文件的版本。它还可以让你手动加载或卸载一个dll文件。

4

工具 -> 附加到进程 - 很容易忘记,但是使用它我可以调试脚本在网页中、在另一个进程中加载的托管代码(想一下插件模型),甚至是非托管代码。但要小心,不要让它自动选择你感兴趣的调试类型。

追踪点(和其他断点功能...右键单击断点并尽情玩耍)!- http://blogs.msdn.com/saraford/archive/2008/06/13/did-you-know-you-can-use-tracepoints-to-log-printf-or-console-writeline-info-without-editing-your-code-237.aspx

即时窗口很棒。

远程调试非常有用,如果您部署应用程序(并且可以访问可重现问题的计算机)。

还有很多其他的。试着使用WinDbg和SoS!


很遗憾,我刚刚得知这些不适用于 Express 版本。 - Michael Haren

3

条件断点非常有用,如果你有重复出现的代码但只在特定条件下失败,例如循环中的代码、从循环调用的方法或从多个线程调用的方法。将break语句放在感兴趣的行并设置其条件以匹配错误情况。(这里有一个快速示例链接。)


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