本快速入门演示如何在 Visual Studio 调试会话中导航,以及如何在会话中查看和更改程序状态。
本 快速入门适用于不熟悉用 Visual Studio 进行调试的开发人员,以及要详细了解在 Visual Studio 调试会话中导航的开发人员。但其中不传授调试本身的技艺。示例代码中的方法仅为演示本主题中所述的调试过程。这些方法并未采用应用程序或函数设计的最佳实 践。实际上,您将快速了解这些方法和应用程序本身,但并不深入研究任何内容。
本快速入门的各节旨在尽可能独立,以使您可跳过其中含有已熟悉信息的任意一节。同时,您也不需要创建示例应用程序;但是,我们建议这样做,并已使该过程尽可能简便易行。
调试器键盘快捷键。Visual Studio 调试器导航同时针对鼠标和键盘进行了优化。本主题中的许多步骤都加入了括号括起的键盘快捷键。例如,(键盘:F5)表示按 F5 键将开始或继续执行调试器。
调试涉及到代码,因此,示例应用程序使用 Windows 应用商店应用程序的框架只是为了创建一个源文件,从中可了解在调试会话中导航的工作方式以及如何检查和更改程序状态。将调用的所有代码均从主页的构造函数中进行调用;不添加控件,也不处理事件。
创建默认 C# Windows 应用商店应用程序。打开 Visual Studio。在主页上,选择“新建项目”链接。在“新建项目”对话框中的“已安装”列表中选择“Visual C#”,然后选择“Windows 应用商店”。在项目模板的列表中,选择“应用程序”。随后 Visual Studio 将创建一个新的解决方案和项目,并显示 MainPage.xaml 设计器和 XAML 代码编辑器。
打开 MainPage.xaml.cs 源文件。右击 XAML 编辑器中的任意位置,然后选择“查看代码”。随后将显示 MainPage.xaml.cs 代码隐藏文件。注意,该文件中仅列出一个方法,即 MainPage() 构造函数。
将 MainPage 构造函数替换为示例代码。删除 MainPage() 方法。访问此链接:调试器导航示例代码(XAML 和 C#),然后将 C# 部分中列出的代码复制到剪贴板。(在浏览器中选择“返回”或帮助查看器返回本快速入门页。)在 Visual Studio 编辑器中,将这段代码粘贴到 partial class MainPage 块中。选择 CTRL + s 以保存文件。
现在即可实践本主题中的示例。
最常用于启动调试会话的方法是从“调试”菜单中选择“启动调试”(键盘:F5)。随后开始执行,并持续执行至抵达某个断点、手动暂停执行、发生异常或应用程序结束为止。
在调试器中暂停执行后,可通过将鼠标悬停在某个活动变量上,在数据提示中查看该变量的值。还可打开“局部变量”和“自动窗口”窗口以查看活动变量及其当前值的列表。将一个或多个变量添加到监视窗口后,可在应用程序继续执行时将精力集中到变量的值上。
暂 停应用程序的执行(也称为中断到调试器中)之后,可控制其余程序代码的执行方式。可继续逐行执行,同时从方法调用移至该方法本身,也可在一个步骤中执行一 个被调用的方法。在逐句通过应用程序时调用这些过程。还可恢复应用程序的标准执行,并运行到已设置的下一个断点或运行到放置光标的行。可随时停止调试会 话。调试器旨在执行必要的清理操作并退出执行。
示例 1
此示例中,在 MainPage.xaml.cs 文件的 MainPage 构造函数中设置一个断点,逐语句执行第一个方法,查看变量值,然后停止调试。
设置断点。在 MainPage 构造函数的语句 methodTrack = "Main Page"; 处设置一个断点。在源代码编辑器的阴影装订线中选择该行(键盘:将光标放置在该行上,然后选择 F9 键)。
随后在装订线中显示该断点图标。
运行到该断点。通过在“调试”菜单上选择“启动调试”(键盘:F5),启动调试会话。
应用程序开始执行,然后在紧接设置了断点的语句之前暂停执行。装订线中的当前行图标指出您所在的位置,并且当前语句为突出显示。
现在由您控制应用程序的执行,可在逐句通过各个程序语句时检查程序状态。
逐语句执行该方法。在“调试”菜单上,选择“逐语句”(键盘:F11)。
注意,调试器将移至下一行,即调用 Example1 方法。再次选择“逐语句”。随后调试器将移至 Example1 方法的入口点。这表示已在调用堆栈上加载了该方法,并且已分配了用于局部变量的内存。
当逐语句执行某行代码时,调试器执行以下操作之一:
-
如果下一个语句不调用您的解决方案中的函数,则调试器执行该语句,移至下一个语句,然后暂停执行。
-
如果该语句调用您的解决方案中的函数,则调试器将移至被调用函数的入口点,然后暂停执行。
继续逐语句执行 Example1 的语句,直至抵达退出点。调试器突出显示该方法的右大括号。
在数据提示中检查变量值。将鼠标悬停在变量名称上时,数据提示中显示该变量的名称、值和类型。
将鼠标悬停在变量 a 上。请注意名称、值和数据类型。将鼠标悬停在变量 methodTrack 上。请再次注意名称、值和数据类型。
在“局部变量”窗口中检查变量值。在“调试”菜单上,指向“窗口”,然后选择“局部变量”。(键盘:Alt+4)。
“局部变量”窗口是函数的参数和变量的一个树视图。对象变量的属性是对象自身的子节点。this 变量是每个对象方法中表示对象自身的一个隐藏参数。在本例下,它表示 MainPage 类。由于 methodTrack 是 MainPage 类的成员,因此其值和数据类型在 this 下的某行中列出。展开 this 节点以查看 methodTrack 信息。
添加针对 methodTrack 变量的监视。本快速入门中全程使用 methodWatch 变量展示在示例中调用的方法。若要更方便地查看该变量的值,请将其添加到某个监视窗口中。在“局部变量”窗口中右击该变量名称,然后选择“添加监视”。
可在一个监视窗口中监视多个变量。只要暂停执行,被监视变量的值(如“局部变量”和数据提示窗口中的值)就会更新。还可从代码编辑器中向监视窗口添加变量。选择要监视的变量,右击,然后选择“添加监视”。
与逐语句执行由父方法调用的某个方法形成对照的是,逐过程执行某个方法将执行子方法,然后当父方法继续执行时,在调用方法中暂停执行。当熟悉某个方法的工作方式并确信执行它不会影响所调查的问题时,可逐过程执行该方法。
逐过程执行某行不包含方法调用的代码时,执行该行如同逐语句执行该行一样。
跳出子方法将继续执行该方法,然后在该方法返回其调用方法后暂停执行。确定某个较长函数的其余部分无关紧要时,可跳出该函数。
逐过程执行和跳出函数都会执行该函数。
示例 2
在此示例中,将逐语句执行、逐过程执行和跳出方法。
在 MainPage 构造函数中调用 Example2 方法。编辑 MainPage 构造函数,将 methodTrack = String.Empty; 之后的一行替换为 Example2();。
运行到该断点。通过在“调试”菜单上选择“启动调试”(键盘:F5),启动调试会话。调试器在断点处暂停执行。
逐过程执行该行代码。在“调试”菜单上,选择“逐过程”(键盘:F10)。调试器按照与逐语句执行 methodTrack = "MainPage"; 语句相同的方式执行该语句。
逐语句执行 Example2 和 Example2_A。选择 F11 键以逐语句执行 Example2 方法。继续逐语句执行 Example2 的语句,直至抵达行 int x = Example2_A();。同样,逐语句执行此行以移至 Example2_A 的入口点。继续逐语句执行 Example2_A 的每个语句,直至返回 Example2。
逐过程执行函数。注意,Example2 中的下一行 int y = Example2_A(); 与上一行基本相同。可安全地逐过程执行此行。选择 F10 键,从 Example2 的继续执行移至对 Example2_A 的第二次调用。选择 F10 以逐过程执行此方法。注意,methodTrack 字符串指示 Example2_A 方法执行了两次。还会注意到调试器立即移至下一行。而不会在 Example2 恢复时暂停执行。
跳出函数。选择 F11 键以逐语句执行 Example2_B 方法。注意,Example2_B 与 Example2_A 区别不大。若要跳出该方法,请在“调试”菜单上选择“跳出”(键盘:Shift + F11)。注意,methodTrack 变量指示已执行 Example2_B,并且调试器已返回 Example2 继续执行的那一点。
停止调试。在“调试”菜单上,选择“停止调试”(键盘:Shift+F5)。这样将结束调试会话。
条件断点指定一种导致调试器暂停执行的情况。该条件由任何可得出 true 或 false 的代码表达式指定。例如,可使用某个条件断点,仅当变量达到某个值时,才在频繁调用的方法中检查程序状态。
运行到光标处类似于设置一次性断点。暂停执行后,可在源代码中选择一行,然后继续执行,直至抵达所选行。例如,可逐句通过方法中的某个循环,然后确定该循环中的代码执行正确。可运行到放置在循环执行后的光标处,而不必逐句通过循环的每次迭代。
有时,在数据提示所在行或变量窗口中难以查看变量值。调试器可在文本可视化工具中显示字符串、HTML 和 XML,该工具在一个可滚动的窗口中呈现该值的格式化视图。
示例 3
此示例中设置一个条件断点,在某个循环的特定迭代处中断,然后运行到放置在该循环后的光标。还可在文本可视化工具中查看变量的值。
在 MainPage 构造函数中调用 Example3 方法。编辑 MainPage 构造函数,将 methodTrack = String.Empty; 之后的一行替换为行 Example3();。
运行到该断点。通过在“调试”菜单上选择“启动调试”(键盘:F5),启动调试会话。调试器在 MainPage 方法中的断点处暂停执行。
逐语句执行 Example3 方法。在“调试”菜单上选择“逐语句”(键盘:F11)以移至 Example3 方法的入口点。继续逐语句执行该方法,直至已迭代 for 块的一个或两个循环。注意,逐语句执行全部 1000 次迭代需要很长时间。
设置条件断点。在代码窗口的左侧装订线中,右击行 x += i;,然后选择“条件”。选中“条件”复选框,然后在文本框中键入 i == 500;。选择“为 true”选项,然后选择“确定”。通过该断点,可在 for 循环的第 500 次迭代时检查该值。
可通过白色十字识别条件断点图标。
运行到该断点。在“调试”菜单上,选择“继续”(键盘:F5)。在“局部变量”窗口中,确认 i 的当前值为 500。请注意,变量 s 显示为一行,并且长度超出窗口许多。
使字符串变量可视化。单击 s 的“值”列中的放大镜图标。
随后将显示“文本可视化工具”窗口,而该字符串的值呈现为一个多行字符串。
运行到光标处。右击行 methodTrack += "->Example3";,然后选择“运行到光标处”(键盘:将光标移至该行;Ctrl + F10)。调试器完成循环迭代,然后在该行暂停执行。
停止调试。在“调试”菜单上,选择“停止调试”(键盘:Shift+F5)。这样将结束调试会话。
在某些情况下,在 Visual Studio 调试器中进入代码后,可更改变量的值,甚至可更改语句的逻辑。此功能称为“编辑并继续”。
在异常处中断时,“编辑并继续”可能尤为有用。现在不必为避免异常而停止再重新开始调试冗长且复杂的过程,可“展开”异常,使执行移至以即将发生异常之前的那一点,然后更改有问题的变量或语句,接着在不会引发异常的状态下继续进行当前的调试会话。
尽 管在许多情况下均可使用“编辑并继续”,但难以指定不支持“编辑并继续”的特定情况,因为这些情况取决于编程语言、程序堆栈的当前状态以及调试器能否在不 损坏进程的情况下更改状态。确定是否支持编辑更改的最佳方法就是尝试进行该更改;在调试器中可立即知道是否支持该更改。
示例 4
在此示例中,将调试器运行到某个异常,后退异常,更正该方法的逻辑,然后更改某个变量的值,以使您可继续执行该方法。
在 MainPage 构造函数中调用 Example4 方法。编辑 MainPage() 构造函数,将 methodTrack = String.Empty; 之后的一行替换为行 Example4();。
运行到该异常。通过在“调试”菜单上选择“启动调试”(键盘:F5),启动调试会话。再次按 F5 以继续执行。调试器在 Example4 方法中的异常处暂停执行,并显示一个异常对话框。
更改程序逻辑。很明显,错误发生在 if 条件中:当 x 等于 0 时应更改 x 的值;但 x 不等于零时不应更改该值。选择“中断”修复该方法的逻辑。当尝试编辑该行时,将显示另一个对话框。
选择“编辑”,然后将行 if (x != 0) 更改为 if (x == 0)。调试器将程序逻辑的更改保留到源文件。
更改变量值。在数据提示中或“局部变量”窗口中检查 x 的值。它仍为 0(零)。如果尝试执行曾导致原始异常的语句,则只会再次引发该异常。可更改 x 的值。在“局部变量”窗口中,双击 x 行的“值”列。将该值从 0 更改为 1。
选择 F11 键以逐语句执行原先曾引发异常的语句。注意,该行执行时不再出错。再次选择 F11。
停止调试。在“调试”菜单上,选择“停止调试”(键盘:Shift+F5)。这样将结束调试会话。