本文介绍适用于 .NET 10 的 .NET SDK 中的新功能和增强功能。 它已针对 RC 2 进行了更新。
.NET 工具改进
特定于平台的 .NET 工具
现在,可以在单个包中发布支持多个 RuntimeIdentifier (RID)的 .NET 工具。 工具作者可以捆绑所有受支持的平台的二进制文件,.NET CLI 将在安装或运行时选择正确的二进制文件。 这使得跨平台工具创作和分发更加容易。
这些改进的工具支持各种包装变体。
- 依赖于框架,平台无关(经典模式,任何安装了 .NET 10 的地方都可以运行)
- 框架依赖,平台特定(更小,针对每个平台进行优化)
- 自包含,平台特定(包含运行时,无需安装 .NET)
- 裁剪版,平台特定 (更小,裁剪未使用的代码)
- 平台特定的 AOT 编译(最大性能和最小部署)
这些新工具的工作方式与常规的已发布应用程序非常相似。因此,任何可用于应用程序的发布选项(例如,自包含、剪裁或 AOT 编译)也同样适用于这些工具。
单次工具执行
现在 dotnet tool exec 可以使用命令执行 .NET 工具,而无需全局或本地安装该工具。 这对于 CI/CD 或临时使用场景尤其有用。
dotnet tool exec --source ./artifacts/package/ dotnetsay "Hello, World!"
Tool package dotnetsay@1.0.0 will be downloaded from source <source>.
Proceed? [y/n] (y): y
_ _ _ _ __ __ _ _ _
| | | | ___ | | | | ___ \ \ / / ___ _ __ | | __| | | |
| |_| | / _ \ | | | | / _ \ \ \ /\ / / / _ \ | '__| | | / _` | | |
| _ | | __/ | | | | | (_) | _ \ V V / | (_) | | | | | | (_| | |_|
|_| |_| \___| |_| |_| \___/ ( ) \_/\_/ \___/ |_| |_| \__,_| (_)
|/
这会在一个命令中下载并运行指定的工具包。 默认情况下,如果工具本地不存在,系统会提示用户确认下载。 除非指定了显式版本(例如, dotnetsay@0.1.0),否则将使用所选工具包的最新版本。
单次工具执行可以与本地工具清单无缝协作运行。 如果从包含 .config/dotnet-tools.json 附近位置运行工具,将使用该配置中的工具版本,而不是可用的最新版本。
新的 dnx 工具执行脚本
该 dnx 脚本提供了一种简化的方式来执行工具。 它将所有参数转发到 dotnet CLI 进行处理,使工具的使用尽可能简单:
dnx dotnetsay "Hello, World!"
dnx命令的实际实现是在CLI本身dotnet,这允许其行为随时间推移而演变。
有关管理 .NET 工具的详细信息,请参阅 “管理 .NET 工具”。
将 any RuntimeIdentifier 与特定于平台的 .NET 工具配合使用
特定于平台的 .NET 工具功能非常适合确保针对预先面向的特定平台优化工具。 但是,有时你不知道要面向的所有平台,有时 .NET 本身将了解如何支持新平台,并且你也希望工具可以在那里运行。
若要使工具以这种方式工作,请将 any 运行时标识符添加到项目文件:
<PropertyGroup>
<RuntimeIdentifiers>
linux-x64;
linux-arm64;
macos-arm64;
win-x64;
win-arm64;
any
</RuntimeIdentifiers>
</PropertyGroup>
此 RuntimeIdentifier 位于平台兼容性检查的“根”位置,由于它声明了对 任何 平台的支持,因此打包的工具将是最兼容的工具类型-一种依赖于框架且与平台无关的 .NET DLL,这需要兼容的 .NET 运行时才能执行。 执行创建工具的 dotnet pack 时,会看到一个用于 any RuntimeIdentifier 的新包,与其他特定于平台的包以及顶级清单包一起显示。
通过 --cli-schema 实现的 CLI 自省
所有 CLI 命令上都提供了一个新 --cli-schema 选项。 使用时,它将输出调用的命令或子命令的 CLI 命令树的 JSON 表示形式。 这对于工具作者、shell 集成和高级脚本非常有用。
dotnet clean --cli-schema
输出提供命令参数、选项和子命令的结构化、计算机可读说明:
{
"name": "clean",
"version": "10.0.100-dev",
"description": ".NET Clean Command",
"arguments": {
"PROJECT | SOLUTION": {
"description": "The project or solution file to operate on. If a file is not specified, the command will search the current directory for one.",
"arity": { "minimum": 0, "maximum": null }
}
},
"options": {
"--artifacts-path": {
"description": "The artifacts path. All output from the project, including build, publish, and pack output, will go in subfolders under the specified path.",
"helpName": "ARTIFACTS_DIR"
}
},
"subcommands": {}
}
将 .NET MSBuild 任务与 .NET Framework MSBuild 配合使用
MSBuild 是用于 .NET 的基础生成系统,可驱动项目构建过程(如命令dotnet build和dotnet pack中所示),并作为项目信息的常规提供者(如命令dotnet list package中所示),例如 dotnet run 等命令隐式使用 MSBuild 来发现项目的执行方式。
运行 dotnet CLI 命令时,使用的 MSBuild 版本是 .NET SDK 附带的版本。 但是,使用 Visual Studio 或直接调用 MSBuild 时,使用的 MSBuild 版本是随 Visual Studio 一起安装的。 这种环境差异会产生一些重要的后果。 最重要的是,在 Visual Studio(或通过 msbuild.exe)中运行的 MSBuild 是 .NET Framework 应用程序,而在 CLI 中 dotnet 运行的 MSBuild 是 .NET 应用程序。 这意味着,在 Visual Studio 中生成或使用 msbuild.exe时,不能使用写入到 .NET 上运行的任何 MSBuild 任务。
从 .NET 10 开始,msbuild.exe 以及 Visual Studio 2026 可以运行为 .NET 构建的 MSBuild 任务。 这意味着,现在可以在 Visual Studio 中生成时使用相同的 MSBuild 任务,也可以在使用 msbuild.exe CLI 进行生成时使用相同的任务。 对于大多数 .NET 用户,这不会更改任何内容。 对于自定义 MSBuild 任务的作者,这意味着您现在可以编写面向 .NET 的任务,并可以在任何地方运行。 此更改的目标是更轻松地编写和共享 MSBuild 任务,并允许任务作者利用 .NET 中的最新功能。 此外,此更改降低了在多目标任务中支持 .NET Framework 和 .NET 的难度,并使处理 MSBuild .NET Framework 执行空间中隐式可用的 .NET Framework 依赖项版本变得更加容易。
配置 .NET 任务
对于任务作者来说,选择加入此新行为很容易。 只需更改 UsingTask 声明,告知 MSBuild 有关你的任务。
<UsingTask TaskName="MyTask"
AssemblyFile="path\to\MyTask.dll"
Runtime="NET"
TaskFactory="TaskHostFactory"
/>
属性Runtime="NET"TaskFactory="TaskHostFactory"告诉 MSBuild 引擎如何运行任务:
-
Runtime="NET"告知 MSBuild 任务是为 .NET 生成的(而不是 .NET Framework)。 -
TaskFactory="TaskHostFactory"告知 MSBuild 使用TaskHostFactory来运行任务,这是 MSBuild 的现有功能,允许任务在进程外(out-of-process)执行。
注意事项和性能优化
前面的示例是开始使用 MSBuild 中的 .NET 任务的最简单方法,但它有一些限制。 由于 TaskHostFactory 总是向进程外运行任务,因此新的 .NET 任务总是运行在独立于 MSBuild 的进程中。 这意味着运行任务会产生一些轻微的开销,因为 MSBuild 引擎和任务通过进程间通信(IPC)而不是进程内通信进行通信。 对于大多数任务,此开销是微不足道的,但对于在生成中运行多次或执行大量日志记录的任务,此开销可能更重要。
稍作调整,即可将任务配置为在通过 dotnet 运行时依然在进程内执行。
<UsingTask TaskName="MyTask"
AssemblyFile="path\to\MyTask.dll"
Runtime="NET"
TaskFactory="TaskHostFactory"
Condition="$(MSBuildRuntimeType) == 'Full'"
/>
<UsingTask TaskName="MyTask"
AssemblyFile="path\to\MyTask.dll"
Runtime="NET"
Condition="$(MSBuildRuntimeType) == 'Core'"
/>
Condition由于 MSBuild 的功能,可以根据 MSBuild 是在 .NET Framework(Visual Studio 或msbuild.exe)还是 .NET(dotnetCLI)中运行,以不同的方式加载任务。 在此示例中,任务在 Visual Studio 或msbuild.exe中运行时是在进程外执行,但在dotnetCLI中运行时是在进程内执行。 这在 dotnet CLI 中运行时提供最佳性能,同时仍允许在 Visual Studio 和msbuild.exe中使用任务。
在 MSBuild 中使用 .NET 任务时,还有一些较小的技术限制,其中最值得注意的是, Host Object MSBuild 任务的功能尚不支持在进程外运行的 .NET 任务。 这意味着,如果任务依赖于主机对象,则它在 Visual Studio msbuild.exe中运行时将不起作用。 计划在未来的版本中增加对主机对象的支持。
基于文件的应用程序功能增强
.NET 10 为基于文件的应用体验带来重大更新,包括发布支持和本机 AOT 功能。 有关基于文件的应用的简介,请参阅基于文件的应用和生成和运行 C# 程序。
具备发布支持和本地 AOT 的以文件为基础的增强应用程序
基于文件的应用现在支持通过 dotnet publish app.cs 命令发布到本机可执行文件,从而更轻松地创建可以重新分发为本机可执行文件的简单应用。 默认情况下,所有基于文件的应用都以本机 AOT 为目标。 如果需要使用与本机 AOT 不兼容的包或功能,可以使用.cs文件中的 #:property PublishAot=false 指令禁用此功能。
基于文件的应用还包括增强的功能:
-
项目引用:支持通过
#:project指令引用项目。 -
运行时路径访问:应用程序文件和目录的路径可在运行时通过
System.AppContext.GetData访问。 - 增强了 shebang 支持:通过改进的 shebang 处理(包括支持无扩展名文件),直接执行 shell 脚本。
项目引用示例
#:project ../ClassLib/ClassLib.csproj
var greeter = new ClassLib.Greeter();
var greeting = greeter.Greet(args.Length > 0 ? args[0] : "World");
Console.WriteLine(greeting);
增强的 shebang 支持示例
现在可以创建直接从 shell 运行的可执行 C# 文件:
#!/usr/bin/env dotnet
Console.WriteLine("Hello shebang!");
对于无扩展名文件:
# 1. Create a single-file C# app with a shebang
cat << 'EOF' > hello.cs
#!/usr/bin/env dotnet
Console.WriteLine("Hello!");
EOF
# 2. Copy it (extensionless) into ~/utils/hello (~/utils is on my PATH)
mkdir -p ~/utils
cp hello.cs ~/utils/hello
# 3. Mark it executable
chmod +x ~/utils/hello
# 4. Run it directly from anywhere
cd ~
hello
这些增强功能使基于文件的应用更加强大,同时保持其简单性,以便快速编写脚本和原型制作方案。
有关本机 AOT 的详细信息,请参阅 .NET 本机 AOT。
修剪由框架提供的包引用
从 .NET 10 开始, NuGet 审核 功能可以修剪项目不使用的 框架提供的包引用 。 默认情况下,此功能针对在最新 SDK 中面向 >.NET 10.0 的项目的所有框架启用。 此更改有助于减少在生成过程中还原和分析的包数,从而缩短生成时间并减少磁盘空间使用量。 这也能够减少来自 NuGet 审计以及其他依赖项扫描机制的误报情况。
启用此功能后,可能会发现应用程序生成的 .deps.json 文件的内容会减少。 .NET 运行时提供的任何包引用都会从生成的依赖项文件中自动删除。
当直接包引用在修剪范围内时,PrivateAssets="all"和IncludeAssets="none"将被应用。
虽然此功能默认为列出的 TPM 启用,但可以通过在RestoreEnablePackagePruning项目文件或 false 文件中将属性设置为禁用此功能。
更一致的命令顺序
从 .NET 10 开始, dotnet CLI 工具包含常见命令的新别名,使它们更易于记住和键入。 下表显示了新命令。
| 新名词优先形式 | 别名 |
|---|---|
dotnet package add |
dotnet add package |
dotnet package list |
dotnet list package |
dotnet package remove |
dotnet remove package |
dotnet reference add |
dotnet add reference |
dotnet reference list |
dotnet list reference |
dotnet reference remove |
dotnet remove reference |
新的名词优先表单符合一般 CLI 标准,使 dotnet CLI 与其他工具更加一致。 虽然动词优先表单继续工作,但最好使用名词优先表单来提高脚本和文档中的可读性和一致性。
CLI 命令默认为交互式终端中的交互模式
现在,在交互式终端中,默认启用 --interactive 标志用于 CLI 命令。 此更改允许命令动态检索凭据或执行其他交互行为,而无需显式设置标志。 对于非交互方案,可以通过指定 --interactive false来禁用交互性。
原生 shell Tab 补全脚本
dotnet CLI 现在支持使用 dotnet completions generate [SHELL] 命令为常用 shell 生成原生 Tab 补全脚本。 支持的 shell 包括bash、fish、nushell和powershellzsh。 这些脚本通过提供更快、更集成的选项卡完成功能来提高可用性。 例如,在 PowerShell 中,可以通过将以下内容添加到 $PROFILE 中来启用补全功能:
dotnet completions script pwsh | out-String | Invoke-Expression -ErrorAction SilentlyContinue
控制台应用可以原生创建容器映像
控制台应用现在可以通过 dotnet publish /t:PublishContainer 创建容器映像,而无需在项目文件中包含 <EnableSdkContainerSupport> 属性。 这使控制台应用与 ASP.NET Core 和 Worker SDK 应用的行为保持一致。
显式控制容器的图像格式
使用新的 <ContainerImageFormat> 属性可以显式地将容器映像的格式设置为 Docker 或 OCI。 此属性替代默认行为,具体取决于基本映像格式以及容器是否为多体系结构。
支持 dotnet test 中的 Microsoft 测试平台
从 .NET 10 开始,dotnet test 原生支持 Microsoft.Testing.Platform。 若要启用此功能,请将以下配置添加到 global.json 文件:
{
"test": {
"runner": "Microsoft.Testing.Platform"
}
}
如需了解更多详情,请参阅使用 dotnet test 进行测试。