70

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

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

跟踪对象实例

使用给定类的多个实例?你怎么能把它们区分开来?在垃圾收集编程之前的日子里,跟踪引用很容易——只需查看内存地址。使用 .NET,您无法做到这一点 - 对象可以四处移动。幸运的是,手表视图允许您右键单击手表并选择“制作对象 ID”。

手表查看 http://img403.imageshack.us/img403/461/52518188cq3.jpg

这会在实例的值之后附加 {1#}、{2#} 等,从而有效地为实例提供唯一标签。它看起来像这样:

编号实例 http://img383.imageshack.us/img383/7351/11732685bl8.jpg

标签在该对象的生命周期内保持不变。

监视变量的有意义的值

默认情况下,监视变量的值是它的类型。如果你想查看它的字段,你必须扩展它,如果有很多字段或者他们做一些复杂的事情,这可能需要很长时间(甚至超时!)。

但是,一些预定义的类型会显示更有意义的信息:

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

有意义的信息 http://img205.imageshack.us/img205/4808/37220487md1.jpg

为我自己的类型拥有它不是很好吗?

唔...

DebuggerDisplay... .NET Reflector 的一些质量时间显示了使用我的自定义类型上的属性可以轻松实现这一点:

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

...重新运行,然后...

达达!http://img60.imageshack.us/img60/926/79816018ha1.jpg

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

打破所有例外

...即使是那些在代码中处理的!我知道,自从我出生以来,我就不知道这件事,但无论如何,这件事发生了——也许有一天这会对某人有所帮助:

每次抛出异常时,您都可以强制调试进程进入调试模式。是否曾经进行了数小时的 bug 搜寻,却发现了这样的一段代码?

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

在这些情况下,捕获所有异常非常方便。这可以从Debug > Exceptions... (Ctrl-Alt-E)启用。勾选您需要的每种异常类型的“抛出”列中的框。


对我来说,那是一些拍打额头的时刻。你愿意分享你的吗?

4

14 回答 14

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

您如何看待最初抛出的异常?在监视窗口中,输入 $exception

于 2008-10-15T13:00:21.587 回答
17

这是我学到的另一个巧妙的技巧:

System.Diagnostics.Debugger.Break()

以编程方式导致调试器在下一条指令上中断。真正好的部分是,这也适用于在发布模式下编译的程序,没有调试信息。

于 2008-10-15T12:03:56.587 回答
12

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

于 2008-10-14T15:17:35.260 回答
9

当然,请查看当天的 VS 提示:

http://blogs.msdn.com/SaraFord/

于 2008-10-14T15:07:58.307 回答
7

我的几个

  • 在工具->选项->调试中取消选中“仅启用我的代码”选项。
  • 条件断点——它们几乎每天都在挽救我的生命
  • 如果事情变得丑陋,请使用 .NET 框架源代码
于 2008-10-15T12:18:07.413 回答
7

两个代码技巧:

我真的很喜欢System.Diagnostics.DebuggerStepThrough属性;您可以将其附加到类、方法或属性上,使 VS 在调试时默认不输入代码。我更喜欢它而不是DebuggerHidden属性,因为如果你真的需要调试它,它仍然允许你在被忽略的代码中放置断点。

另一个(有时)有用的调用是System.Diagnostics.Debugger.Launch();当执行成功时,您将看到“选择调试器”对话框,并且调试器将启动。有点粗鲁,但在附加到进程时特别有用,例如一个由另一个进程生成并立即执行您的代码的进程。

于 2009-09-02T13:41:55.603 回答
6

.load sos在即时窗口中:)

于 2008-10-15T12:55:26.513 回答
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!

于 2008-10-15T12:18:45.213 回答
4

我发现“模块”窗口很多时候都很有用。它告诉调试器是否加载了所需的 dll 以及加载了哪个版本的 dll。它还允许您手动加载或卸载 dll。

于 2008-12-30T19:13:21.343 回答
3

如果您的代码重复很多但仅在一组特定条件下失败(例如循环中的代码、从循环调用的方法或从多个线程调用的方法),条件中断非常有用。将 break 语句放在感兴趣的行并设置其条件以匹配错误情况。(这里有一个简单的例子。)

于 2008-10-15T12:17:42.283 回答
2

来自我的两个:我希望每个人都使用的一个:

Debug.Assert(<condition>, <message>)

第二个DebuggerHidden:

<DebuggerHidden()> _
Public Sub ReadDocumentProperty(ByVal propertyName As String, ByRef PropVal As Integer, ByVal DefaultVal As Integer)
    Try
        Dim prop As Office.DocumentProperty
        prop = CustomProps.Item(propertyName)
        PropVal = CType(prop.Value, Integer)
    Catch
        PropVal = DefaultVal
    End Try
End Sub

即使你设置了Debug、Exceptions、Break on throwed exceptions,这里的异常也不会被捕获。

于 2008-12-30T17:12:03.897 回答
1

创建一个宏以附加到进程并分配给未使用的键盘快捷键。比去快得多:调试->附加到进程->在进程列表中搜索进程->...

于 2010-12-04T01:02:45.133 回答
1

即使我们没有设置任何调试点,如何将 IDE 设置为在发生异常时中断异常。

调试--> 异常--> 公共语言运行时异常--> 抛出

这使得查找隐藏的异常处理问题变得轻而易举。实际上,这是每个开发人员在整个开发过程中都应该设置的一种设置,以避免出现任何未经处理甚至处理的异常。

于 2011-03-16T16:45:59.197 回答
0

在非托管代码中,您可以设置“数据断点”。他们使用 CPU 的调试寄存器发出一个 INT3,并且调试器在该指令上停止,在运行时没有开销(在旧版本中,调试器逐步检查内存......慢!)

如果您在已知地址有一些损坏(堆栈/堆变量被破坏),这很有用。

此外,可以自定义 ide\packages\debugger 中的 AutoExp.dat 以显示您的数据结构。

指针,mb 在监视窗口中显示十六进制转储 http://msdn.microsoft.com/en-us/magazine/dd252945.aspx

嗯!

于 2010-08-24T16:39:02.287 回答