global.json仅控制dotnet CLI命令(如build、run)使用的SDK版本,不影响运行时版本;其生效需满足命名全小写、位于项目根目录或上级目录、JSON格式合法且仅含sdk字段等条件。

global.json 是什么,它到底管不管用
它只影响 dotnet CLI 命令的行为,比如 dotnet build、dotnet run,**不控制项目实际运行时的 .NET 运行时版本**。项目最终跑哪个 runtime,由 <targetframework></targetframework>(如 net6.0)和系统已安装的 SDK 共同决定。global.json 的作用只是告诉 CLI:“在这个目录及子目录下,优先用这个 SDK 版本来还原、编译”。
常见错误现象:dotnet --version 输出和 global.json 里写的不一致 → 很可能你没在正确的目录下执行命令,或者文件没被识别(路径、格式、命名大小写不对)。
- 文件必须叫
global.json,全小写,不能是Global.json或GLOBAL.JSON - 必须放在要生效的项目的**根目录或其任意上级目录**(CLI 会向上逐级查找,找到第一个就停)
- 内容必须是合法 JSON,且顶层只有
sdk字段;多一个逗号、少一个引号都会让 CLI 忽略它
怎么写一个能生效的 global.json
最简可用结构就两行:指定版本号 + 可选是否允许预览版。不要加注释,不要加多余字段(比如 msbuild-sdks 不属于 sdk 配置范畴)。
{
"sdk": {
"version": "7.0.400",
"allowPrerelease": false
}
}
使用场景:团队统一 SDK 版本,避免因本地装了多个 SDK 导致构建结果不一致;CI/CD 中锁定构建环境。
-
version是 SDK 版本号,不是 runtime 版本(如7.0.400对应 SDK 7.0.400,它自带 runtime 7.0.x) - 设为
"allowPrerelease": true才能匹配像8.0.100-rc.2.23502.2这类预发布版 - 如果写成
"version": "7.0"(不带补丁号),CLI 会找满足7.0.x的最新已安装 SDK,行为不确定,不推荐
为什么写了 global.json 却没生效
最常踩的坑是 CLI 没读到它,而不是配置写错了。检查顺序比改内容更重要。
- 执行
dotnet --list-sdks,确认你要的版本确实在列表里(global.json 不会帮你装 SDK) - 执行
dotnet --info,看输出顶部的 “SDK Version” 和 “Path to SDKs”,确认当前工作目录是否在 global.json 影响范围内 - 执行
dotnet --version后立刻再执行dotnet --info,对比两者 SDK 版本是否一致;不一致说明 global.json 没起作用 - Windows 下注意路径权限:如果 global.json 在
C:\Program Files\下,普通用户可能无权读取,CLI 会静默跳过
global.json 和 csproj 里的 TargetFramework 有什么关系
完全独立,但协同工作。前者管“用哪个 SDK 编译”,后者管“编译出的程序依赖哪个 runtime”。你可以用 SDK 8.0 编译 <targetframework>net6.0</targetframework> 的项目,只要 SDK 8.0 支持 net6.0(它支持)。
性能/兼容性影响:高版本 SDK 编译低版本目标框架通常没问题,但反过来不行(比如用 SDK 6.0 编译 net8.0 项目会报错)。也不建议用太老的 SDK(如 5.0)编译新框架项目,可能缺失新语言特性支持或生成警告。
- SDK 版本决定 MSBuild 工具链、Razor 编译器、NuGet 还原逻辑等底层能力
- TargetFramework 决定引用哪些 BCL 程序集、能否使用
required member等 C# 11 特性 - 二者不匹配时,错误信息通常是
The SDK 'Microsoft.NET.Sdk' specified could not be found或NETSDK1045,不是语法错误
最容易被忽略的是:global.json 生效范围是**目录树**,不是单个项目。一个解决方案里多个项目,只要它们共享某个祖先目录下的 global.json,就会被一起约束。改一个地方,可能悄悄影响好几个子项目。










