调试
你可以使用 Microsoft C# 扩展在 Visual Studio Code 中调试 C# 应用程序。
运行和调试
C# 扩展与 C# Dev Kit 一起提供了多种运行和调试 C# 应用程序的方法。
若要在不使用 C# Dev Kit 的情况下运行和调试,请参阅 Microsoft C# 扩展的 GitHub 页面了解相关文档。
使用 F5 进行调试
在安装了 C# Dev Kit 扩展,并且“调试”视图中没有可供选择的调试配置时,你可以通过打开一个 .cs
文件然后按 F5 来开始调试你的项目。调试器会自动找到你的项目并开始调试。如果你有多个项目,它会提示你想要开始调试哪个项目。
你还可以从 VS Code 侧边栏的**运行和调试**视图启动调试会话。更多信息请参见在 VS Code 中调试。
使用解决方案资源管理器进行调试
安装 C# Dev Kit 扩展后,当你在解决方案资源管理器中右键单击你的项目时,会有一个**调试**上下文菜单。
有三个选项
- **启动新实例 (Start New Instance)** - 这将启动你的项目并附加一个调试器。
- **开始执行(不调试) (Start without Debugging)** - 这将在不附加调试器的情况下运行你的项目。
- **单步执行新实例 (Step into New Instance)** - 这将启动你的项目并附加一个调试器,但在代码的入口点处停止。
使用命令面板进行调试
安装 C# Dev Kit 扩展后,你也可以通过使用**调试: 选择并开始调试**命令,从命令面板 ⇧⌘P (Windows、Linux Ctrl+Shift+P) 开始调试。
注意:这会向你的调试下拉列表中添加一个启动配置条目。
使用动态(内存中)启动配置进行调试
安装 C# Dev Kit 扩展后,你可以创建动态启动配置。如何创建它们取决于你的项目是否已有 launch.json
文件。
已有的 launch.json
如果你已有 launch.json
,你可以转到“调试”视图,选择下拉菜单,然后选择 C#
选项。这应该会给你一个启动目标的选择,你可以将其添加到你的下拉列表中。选择后,你可以按 F5 或用新生成的配置点击**开始调试**。
没有 launch.json
如果你的项目中没有 launch.json
,你可以在“调试”视图中的**显示所有自动调试配置**中添加和访问这些动态配置。
移除动态(内存中)启动配置
你可以通过命令面板 ⇧⌘P (Windows、Linux Ctrl+Shift+P) 并使用**调试: 选择并开始调试**命令来移除生成的配置。
下拉菜单中列出了你所有现有的调试配置。如果你将鼠标悬停在动态配置上,右侧会出现一个可点击的垃圾桶图标。你可以选择该图标来移除动态配置。
使用编辑器中的调试/运行按钮进行调试
当编辑器中打开了一个 .cs
文件时,可以通过位于编辑器窗口右上角的按钮来访问运行和调试选项。这些操作将使用当前文件来查询项目系统,并确定要启动的关联项目。
这两个选项是
-
运行与此文件关联的项目
:这将使用调试适配器以noDebug: true
模式启动你的程序。 -
调试与此文件关联的项目
:这将在调试器下启动你的程序。
使用 launch.json 进行调试
如果你正在使用 C# Dev Kit,我们建议不要使用此选项。但是,如果你需要直接修改调试配置,请参见为 C# 调试配置 launch.json。
附加到进程
你可以通过命令面板 ⇧⌘P (Windows、Linux Ctrl+Shift+P) 并运行**调试: 附加到 .NET 5+ 或 .NET Core 进程**命令来附加到 C# 进程。
配置选项
有许多选项和设置可用于配置调试器。你可以使用 launchSettings.json
、VS Code 用户设置来修改你的调试选项,或者直接修改你的 launch.json
。
launchSettings.json
如果你有来自 Visual Studio 的 launchSettings.json
文件,你应该能看到你的配置文件列在使用F5 运行或从命令面板运行时。
更多详情请参考配置 C# 调试。
用户设置
如果你希望在使用 C# 调试器时更改某些设置,你可以在 文件 > 首选项 > 设置 (⌘, (Windows, Linux Ctrl+,)) 下找到这些选项,并搜索它们。
csharp.debug.stopAtEntry
- 如果为 true,调试器应在目标的入口点处停止。此选项默认为false
。csharp.debug.console
- 启动控制台项目时,指示目标程序应在哪个控制台中启动。注意: 此选项仅用于 'dotnet' 调试配置类型。internalConsole
[默认] - VS Code 的调试控制台。此模式允许你在一个地方看到来自调试器和目标程序的消息。更多详情请参考完整文档。integratedTerminal
- VS Code 的集成终端。externalTerminal
- 可通过用户设置配置的外部终端。
csharp.debug.sourceFileMap
- 将构建时路径映射到本地源位置。所有构建时路径的实例都将被替换为本地源路径。
示例
{\"<构建时路径>\":\"<本地源路径>\"}
csharp.debug.justMyCode
- 启用时(默认),调试器仅显示和单步进入用户代码(“我的代码”),忽略系统代码和其他已优化或没有调试符号的代码。更多信息。csharp.debug.requireExactSource
- 要求当前源代码与 PDB 匹配的标志。此选项默认为true
。csharp.debug.enableStepFiltering
- 启用跳过属性和运算符的标志。此选项默认为true
。csharp.debug.logging.exceptions
- 决定是否应将异常消息记录到输出窗口的标志。此选项默认为true
。csharp.debug.logging.moduleLoad
- 决定是否应将模块加载事件记录到输出窗口的标志。此选项默认为true
。csharp.debug.logging.programOutput
- 在不使用外部控制台时,决定是否应将程序输出记录到输出窗口的标志。此选项默认为true
。csharp.debug.logging.diagnosticsLog
- 用于诊断调试器问题的各种设置。csharp.debug.logging.browserStdOut
- 决定是否应将启动 Web 浏览器时产生的 stdout 文本记录到输出窗口的标志。此选项默认为true
。csharp.debug.logging.elapsedTiming
- 如果为 true,引擎日志记录将包含adapterElapsedTime
和engineElapsedTime
属性,以指示请求所花费的时间(以微秒为单位)。此选项默认为false
。csharp.debug.logging.threadExit
- 控制当目标进程中的线程退出时是否记录消息。此选项默认为false
。csharp.debug.logging.processExit
- 控制当目标进程退出或调试停止时是否记录消息。此选项默认为true
。csharp.debug.suppressJITOptimizations
- 如果为 true,当一个优化的模块(在 Release 配置中编译的 .dll)在目标进程中加载时,调试器会要求即时编译器生成禁用优化的代码。更多信息csharp.debug.symbolOptions.searchPaths
- 用于搜索 .pdb 文件的符号服务器 URL(例如:http://MyExampleSymbolServer
)或目录(例如:/build/symbols)的数组。除了默认位置(模块旁边和 pdb 最初放置的路径)之外,还将在这些目录中搜索。csharp.debug.symbolOptions.searchMicrosoftSymbolServer
- 如果为true
,则将 Microsoft 符号服务器 (https://msdl.microsoft.com/download/symbols
) 添加到符号搜索路径中。如果未指定,此选项默认为false
。csharp.debug.symbolOptions.searchNuGetOrgSymbolServer
- 如果为true
,则将 NuGet.org 符号服务器 (https://symbols.nuget.org/download/symbols
) 添加到符号搜索路径中。如果未指定,此选项默认为false
。csharp.debug.symbolOptions.cachePath
- 从符号服务器下载的符号应缓存的目录。如果未指定,在 Windows 上,调试器默认为%TEMP%\\SymbolCache
,在 Linux 和 macOS 上,调试器默认为~/.dotnet/symbolcache
。csharp.debug.symbolOptions.moduleFilter.mode
- 控制模块过滤器在哪两种基本操作模式下运行。loadAllButExcluded
- 为所有模块加载符号,除非该模块在excludedModules
数组中。loadOnlyIncluded
- 不尝试为任何模块加载符号,除非它在includedModules
数组中,或者通过includeSymbolsNextToModules
设置被包含。
csharp.debug.symbolOptions.moduleFilter.excludedModules
- 调试器不应为其加载符号的模块数组。支持通配符(例如:MyCompany.*.dll)。此属性将被忽略,除非mode
设置为loadAllButExcluded
。csharp.debug.symbolOptions.moduleFilter.includedModules
- 调试器应为其加载符号的模块数组。支持通配符(例如:MyCompany.*.dll)。此属性将被忽略,除非mode
设置为loadOnlyIncluded
。csharp.debug.symbolOptions.moduleFilter.includeSymbolsNextToModules
- 如果为 true,对于不在includedModules
数组中的任何模块,调试器仍将检查模块本身旁边和启动可执行文件旁边,但不会检查符号搜索列表中的路径。此选项默认为true
。此属性将被忽略,除非mode
设置为loadOnlyIncluded
。csharp.debug.allowFastEvaluate
- 当为 true(默认状态)时,调试器将通过模拟简单属性和方法的执行来尝试更快的求值。csharp.experimental.debug.hotReload
- 当为 true 时,如果目标应用程序支持热重载,调试器将启用在调试时应用更改的功能。csharp.debug.hotReloadOnSave
- 当为 true(默认状态)时,调试器将在文件保存时自动应用代码更改。csharp.debug.hotReloadVerbosity
- 控制**C# 热重载**输出窗口的日志记录详细程度。可以设置为minimal
(默认)、detailed
或diagnostic
。如果热重载开始出现异常行为,建议提高详细程度级别。
断点
C# 调试器支持各种断点,例如源代码行断点、条件断点和日志点。
断点 - 条件断点
借助表达式求值,调试器也支持条件断点。你可以设置你的断点在表达式求值为 true 时中断。
断点 - 函数断点
调试器还支持函数断点。你可以通过点击“调试”窗格中“断点”部分的 +
来设置断点,使其在特定函数处中断。
断点 - 日志点
日志点(在 Visual Studio 中也称为跟踪点)允许你向调试控制台发送输出,而无需编辑代码。它们与断点不同,因为它们不会停止应用程序的执行流程。
要添加日志点,请在代码行旁边的最左侧边距处右键单击。选择**添加日志点**并输入你想要记录的消息。任何在花括号('{' 和 '}')之间的表达式都将在命中日志点时被求值。
日志消息中还支持以下令牌
标记 | 描述 | 示例输出 |
---|---|---|
$FILEPOS | 当前源文件位置 | C:\sources\repos\Project\Program.cs:4 |
$FUNCTION | 当前函数名 | Program.<Main>$ |
$ADDRESS | 当前指令 | 0x00007FFF83A54001 |
$TID | 线程 ID | 20668 |
$PID | 进程 ID | 10028 |
$TNAME | 线程名称 | <无线程名称> |
$PNAME | 进程名称 | C:\sources\repos\Project\bin\Debug\net7.0\console.exe |
$CALLER | 调用函数名 | void console.dll!Program.Foo() |
$CALLSTACK | 调用堆栈 | void console.dll!Program.Bar() void console.dll!Program.Foo() void console.dll!Program.<Main>$(string[] args) [外部代码] |
$TICK | Tick 计数(来自 Windows GetTickCount) | 28194046 |
$HITCOUNT | 此断点被命中的次数 | 5 |
断点 - 触发断点
触发断点是一种在另一个断点命中后自动启用的断点。当代码中出现仅在特定先决条件发生后才出现的故障情况时,它们非常有用。
可以通过右键单击字形边距,选择 添加触发断点,然后选择哪个其他断点启用此断点来设置触发断点。
在异常时停止
C# 调试器支持配置选项,用于设置当异常被抛出或捕获时调试器是否停止。这是通过**运行**视图中**断点**部分中的两个不同条目来完成的
请注意,在首次使用 C# 调试器调试该文件夹之前,**断点**部分将缺少这些条目。
勾选**所有异常**将配置调试器在异常被抛出时停止。如果仅我的代码已启用(默认情况下是启用的),则如果异常在库代码中被内部抛出并捕获,调试器将不会中断。但是,如果异常在库代码中被抛出并返回到用户代码,调试器将会中断。
勾选**用户未处理的异常**将配置调试器在异常在用户代码中抛出或穿过用户代码后,在非用户代码中被捕获时停止。成为用户未处理的异常并不总是被调试进程中的一个 bug——可能用户代码正在实现一个 API,并且预期会引发异常。在许多情况下,确实存在问题,所以默认情况下,当异常成为用户未处理时,调试器会停止。
异常条件
两个复选框都支持条件,以便仅在选定的异常类型上中断。要编辑条件,请选择铅笔图标(见上图)或右键单击条目并调用**编辑条件**。该条件是一个逗号分隔的异常类型列表,表示在这些类型上中断;如果列表以 '!' 开头,则表示要忽略的异常类型列表。
示例条件
示例条件值 | 结果 |
---|---|
System.NullReferenceException | 这只会因空引用异常而中断。 |
System.NullReferenceException, System.InvalidOperationException | 这会在空引用异常和无效操作异常时中断。 |
!System.Threading.Tasks.TaskCanceledException | 这会在除了任务取消之外的所有异常上中断。 |
!System.Threading.Tasks.TaskCanceledException, System.NotImplementedException | 这会在除了任务取消和未实现之外的所有异常上中断。 |
表达式求值
调试器还允许您在**监视**窗口以及调试控制台中对表达式求值。
热重载
安装 C# Dev Kit 扩展后,调试器允许您在调试时应用 C# 代码更改。
为了启用热重载,csharp.experimental.debug.hotReload
必须设置为 true,更多信息请参见用户设置。只有当目标调试器引擎支持应用代码更改时,热重载会话才会启动。
支持的项目和场景
C# Dev Kit 支持“经典”的热重载体验,也称为“编辑并继续”。无论您是停在断点上还是程序正在运行,都可以在调试时应用代码更改。
截至 2023 年 11 月,一些功能如 MetadataUpdateHandler
(它能使 ASP.NET Core 应用程序在做出更改后自动刷新浏览器)尚不可用。在不调试的情况下应用代码更改也不受支持。
运行时在 .NET 8 中增加了在 Linux/macOS 上调试时应用更改的支持,因此在这些操作系统上运行的 .NET 应用应用代码更改时,需要 .NET 8+ 的运行时版本。
应用程序类型 | 支持使用 C# Dev Kit 进行热重载 | 需要 .NET 8+ |
---|---|---|
控制台 | ✅ | 仅限 Linux/macOS |
测试项目 | ✅ | 仅限 Linux/macOS |
类库项目 | ✅ | 仅限 Linux/macOS |
ASP.NET Core | ⚠️* *目前仅支持对 .cs 文件的更改* |
仅限 Linux/macOS |
MAUI | ❌* *即将推出* | -- |
Unity | ❌ | -- |
有关 C# Dev Kit 当前支持的项目的更多信息,请参阅支持的项目。另请参阅 C# Dev Kit FAQ 以获取有关排查其他不支持场景的更多信息。
如何应用代码更改
一旦热重载会话开始并进行了新的更改,您可以通过以下任何操作将这些更改应用于您的应用程序
操作 | 说明 |
---|---|
热重载 Ctrl+Shift+Enter |
应用代码更改,可从**调试工具栏**获得。 |
保存文件 ⌘S (Windows, Linux Ctrl+S) |
如果 csharp.debug.hotReloadOnSave 设置为 true,则开始应用代码更改。更多信息请参见用户设置。 |
继续 / 单步跳过 / 单步进入 / 单步跳出 F5 / F10 / F11 / ⇧F11 (Windows, Linux Shift+F11) |
当在中断状态下(例如,在断点处停止时)进行更改时,这些命令将自动应用它们。 |
后续步骤
继续阅读以了解:
- 调试 - 了解如何在 VS Code 中为任何语言的项目使用调试器。