当前位置: 首页 > news >正文

理解 Visual Studio 解决方案文件格式(.sln)

一般情况下我们并不需要关心 Visual Studio 解决方案文件格式(.sln),因为 Visual Studio 对解决方案文件的自动修复能力是非常强的。但是如果遇到自动解冲突错误或者编译不通过了,那么此文件还是需要手工修改的。

本文介绍 Visual Studio 解决方案(.sln)文件的格式。


本文内容

    • 基本概念
    • 结构
      • 版本信息
      • 项目信息
        • Project
        • ProjectSection
      • 全局信息

基本概念

Visual Studio 的解决方案文件由这三个部分组成:

  • 版本信息
    • Microsoft Visual Studio Solution File, Format Version 12.00
    • # Visual Studio Version 16
    • VisualStudioVersion = 16.0.28606.126
    • MinimumVisualStudioVersion = 10.0.40219.1
  • 项目信息
    • Project
    • EndProject
  • 全局信息
    • Global
    • EndGlobal

虽然看起来是三个独立的部分,但其实除了版本号之外,项目信息和全局信息还是有挺多耦合部分的。

比如我们来看一个 sln 文件的例子,是一个最简单的只有一个项目的 sln 文件:

只有一个项目的 sln 文件

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29102.190
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Walterlv.Demo", "Walterlv.Demo\Walterlv.Demo.csproj", "{DC0B1D44-5DF4-4590-BBFE-072183677A78}"
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|Any CPU = Debug|Any CPU
		Release|Any CPU = Release|Any CPU
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
		{DC0B1D44-5DF4-4590-BBFE-072183677A78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{DC0B1D44-5DF4-4590-BBFE-072183677A78}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{DC0B1D44-5DF4-4590-BBFE-072183677A78}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{DC0B1D44-5DF4-4590-BBFE-072183677A78}.Release|Any CPU.Build.0 = Release|Any CPU
	EndGlobalSection
	GlobalSection(SolutionProperties) = preSolution
		HideSolutionNode = FALSE
	EndGlobalSection
	GlobalSection(ExtensibilityGlobals) = postSolution
		SolutionGuid = {F2F1AD1B-207B-4731-ABEB-92882F89B155}
	EndGlobalSection
EndGlobal

下面我们来一一说明。

结构

版本信息

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29102.190
MinimumVisualStudioVersion = 10.0.40219.1

记录文件的格式版本是 12.0。使用 Visual Studio 2019 编辑/创建。

这里有一个小技巧,这里的 VisualStudioVersion 版本号设置为 15.0 会使得打开 sln 文件的时候默认使用 Visual Studio 2017,而设置为 16.0 会使得打开 sln 文件的时候默认使用 Visual Studio 2019。

项目信息

Project

Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Walterlv.Demo", "Walterlv.Demo\Walterlv.Demo.csproj", "{DC0B1D44-5DF4-4590-BBFE-072183677A78}"
EndProject

项目信息至少由两行组成,第一行标记项目信息开始,而最后一行表示信息结束。

其格式为:

Project("{项目类型}") = "项目名称", "项目路径", "项目 Id"
EndProject

你可以在我的另一篇博客中找到项目类型:

  • 解决方案文件 sln 中的项目类型 GUID

但是本文列举几个 .NET/C# 项目中的常见类型:

  • 9A19103F-16F7-4668-BE54-9A1E7A4F7556 SDK 风格的 C# 项目文件
  • FAE04EC0-301F-11D3-BF4B-00C04F79EFBC 传统风格的 C# 项目文件
  • 2150E333-8FDC-42A3-9474-1A3956D46DE8 解决方案文件夹

关于 SDK 风格的项目文件,可以阅读我的另一篇博客:

  • 将 WPF、UWP 以及其他各种类型的旧 csproj 迁移成 Sdk 风格的 csproj - walterlv

项目名称和项目路径不必多说,都知道。对于文件夹而言,项目名称就是文件夹的名称,而项目路径也是文件夹的名称。

项目 Id 是在解决方案创建项目的过程中生成的一个新的 GUID,每个项目都不一样。对于 SDK 风格的 C# 项目文件,csproj 中可以指定项目依赖,而如果没有直接的项目依赖,而只是解决方案编译级别的依赖,那么也可以靠 sln 文件中的项目 Id 来指定项目的依赖关系。另外,也通过项目 Id 来对项目做一些编译上的解决方案级别的配置。

ProjectSection

ProjectEndProject 的内部还可以放 ProjectSection

比如对于解决方案文件夹,可以包含解决方案文件:

Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B002382D-4C9E-4F08-85E5-F12E2C061F5A}"
	ProjectSection(SolutionItems) = preProject
		.gitattributes = .gitattributes
		.gitignore = .gitignore
		README.md = README.md
		build\Version.props = build\Version.props
	EndProjectSection
EndProject

这个解决方案文件夹中包含了四个文件,其路径分别记录在了 ProjectSection 节点里面。

ProjectSection 还可以记录项目依赖关系(非项目之间的真实依赖,而是解决方案级别的编译依赖):

Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Walterlv.Demo", "Walterlv.Demo\Walterlv.Demo.csproj", "{DC0B1D44-5DF4-4590-BBFE-072183677A78}"
	ProjectSection(ProjectDependencies) = postProject
		{98FF9756-B95A-4FDB-9858-5106F486FBF3} = {98FF9756-B95A-4FDB-9858-5106F486FBF3}
	EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Walterlv.Demo2", "Walterlv.Demo2\Walterlv.Demo2.csproj", "{98FF9756-B95A-4FDB-9858-5106F486FBF3}"
EndProject

在这一段节点里面,我们的 Walterlv.Demo 项目依赖于另外一个 Walterlv.Demo2 项目。依赖是以 项目 Id = 项目 Id 的方式写出来的;如果有多个依赖,那么就写多行。不用吐槽为什么一样还要写两遍,因为这是一个固定的格式,后面我们会介绍一些全局配置里面会有两个不一样的。

关于设置项目依赖关系的方法,除了 sln 文件里面的设置之外,还有通过设置项目依赖属性的方式,详情可以阅读:

  • 两种方法设置 .NET/C# 项目的编译顺序,而不影响项目之间的引用

全局信息

一个全局信息的例子如下:

Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|Any CPU = Debug|Any CPU
		Release|Any CPU = Release|Any CPU
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
		{DC0B1D44-5DF4-4590-BBFE-072183677A78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{DC0B1D44-5DF4-4590-BBFE-072183677A78}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{DC0B1D44-5DF4-4590-BBFE-072183677A78}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{DC0B1D44-5DF4-4590-BBFE-072183677A78}.Release|Any CPU.Build.0 = Release|Any CPU
		{98FF9756-B95A-4FDB-9858-5106F486FBF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{98FF9756-B95A-4FDB-9858-5106F486FBF3}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{98FF9756-B95A-4FDB-9858-5106F486FBF3}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{98FF9756-B95A-4FDB-9858-5106F486FBF3}.Release|Any CPU.Build.0 = Release|Any CPU
	EndGlobalSection
	GlobalSection(SolutionProperties) = preSolution
		HideSolutionNode = FALSE
	EndGlobalSection
	GlobalSection(ExtensibilityGlobals) = postSolution
		SolutionGuid = {F2F1AD1B-207B-4731-ABEB-92882F89B155}
	EndGlobalSection
EndGlobal

在这个全局信息的例子中,为解决方案指定了两个配置(Configuration),DebugRelease,平台都是 Any CPU。同时也为每个项目指定了单独的配置种类,可供选择,每一行都是 项目的配置 = 解决方案的配置 表示此项目的此种配置在解决方案的某个全局配置之下。

如果我们将这两个项目放到文件夹中,那么我们可以额外看到一个新的全局配置 NestedProjects 字面意思是说 {DC0B1D44-5DF4-4590-BBFE-072183677A78}{98FF9756-B95A-4FDB-9858-5106F486FBF3} 两个项目在 {20B61509-640C-492B-8B33-FB472CCF1391} 项目中嵌套,实际意义代表 Walterlv.DemoWalterlv.Demo2 两个项目在 Folder 文件夹下。

GlobalSection(NestedProjects) = preSolution
    {DC0B1D44-5DF4-4590-BBFE-072183677A78} = {20B61509-640C-492B-8B33-FB472CCF1391}
    {98FF9756-B95A-4FDB-9858-5106F486FBF3} = {20B61509-640C-492B-8B33-FB472CCF1391}
EndGlobalSection

在同一个文件夹下

上图解决方案下的整个解决方案全部内容如下:

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29102.190
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Walterlv.Demo", "Walterlv.Demo\Walterlv.Demo.csproj", "{DC0B1D44-5DF4-4590-BBFE-072183677A78}"
	ProjectSection(ProjectDependencies) = postProject
		{98FF9756-B95A-4FDB-9858-5106F486FBF3} = {98FF9756-B95A-4FDB-9858-5106F486FBF3}
	EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Walterlv.Demo2", "Walterlv.Demo2\Walterlv.Demo2.csproj", "{98FF9756-B95A-4FDB-9858-5106F486FBF3}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Folder", "Folder", "{20B61509-640C-492B-8B33-FB472CCF1391}"
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|Any CPU = Debug|Any CPU
		Release|Any CPU = Release|Any CPU
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
		{DC0B1D44-5DF4-4590-BBFE-072183677A78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{DC0B1D44-5DF4-4590-BBFE-072183677A78}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{DC0B1D44-5DF4-4590-BBFE-072183677A78}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{DC0B1D44-5DF4-4590-BBFE-072183677A78}.Release|Any CPU.Build.0 = Release|Any CPU
		{98FF9756-B95A-4FDB-9858-5106F486FBF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{98FF9756-B95A-4FDB-9858-5106F486FBF3}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{98FF9756-B95A-4FDB-9858-5106F486FBF3}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{98FF9756-B95A-4FDB-9858-5106F486FBF3}.Release|Any CPU.Build.0 = Release|Any CPU
	EndGlobalSection
	GlobalSection(SolutionProperties) = preSolution
		HideSolutionNode = FALSE
	EndGlobalSection
	GlobalSection(NestedProjects) = preSolution
		{DC0B1D44-5DF4-4590-BBFE-072183677A78} = {20B61509-640C-492B-8B33-FB472CCF1391}
		{98FF9756-B95A-4FDB-9858-5106F486FBF3} = {20B61509-640C-492B-8B33-FB472CCF1391}
	EndGlobalSection
	GlobalSection(ExtensibilityGlobals) = postSolution
		SolutionGuid = {F2F1AD1B-207B-4731-ABEB-92882F89B155}
	EndGlobalSection
EndGlobal

我的博客会首发于 https://blog.walterlv.com/,而 CSDN 会从其中精选发布,但是一旦发布了就很少更新。

如果在博客看到有任何不懂的内容,欢迎交流。我搭建了 dotnet 职业技术学院 欢迎大家加入。

知识共享许可协议

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:https://walterlv.blog.csdn.net/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。

相关文章:

  • nuget.exe 还原解决方案 NuGet 包的时候出现错误:调用的目标发生了异常。Error parsing the nested project section in solution file
  • 找出 .NET Core SDK 是否使用预览版的全局配置文件在哪里(探索篇)
  • 如何在 Visual Studio 2019 中设置使用 .NET Core SDK 的预览版(全局生效)
  • 使用基于 Roslyn 的 Microsoft.CodeAnalysis.PublicApiAnalyzers 来追踪项目的 API 改动,帮助保持库的 API 兼容性
  • Visual Studio 2019 中使用 .NET Core 预览版 SDK 的全局配置文件在哪里?
  • 推荐几款连字字体,在代码编辑器中启用连字字体(Visual Studio Code)
  • 找回你 C 盘丢失的空间(SpaceSniffer)
  • System.InvalidOperationException:“寄宿 HWND 必须是子窗口。”
  • 通过 AppSwitch 禁用 WPF 内置的触摸让 WPF 程序可以处理 Windows 触摸消息
  • 如何为非常不确定的行为(如并发)设计安全的 API,使用这些 API 时如何确保安全
  • 通过 mklink 收集本地文件系统的所有 NuGet 包输出目录来快速调试公共组件代码
  • 设计一个 .NET 可用的弱引用集合(可用来做缓存池使用)
  • 使用 C# 中的 dynamic 关键字调用类型方法时可能遇到的各种问题
  • 程序员可能会使用的各种命名规则
  • System.InvalidOperationException:“BuildWindowCore 无法返回寄宿的子窗口句柄。”
  • [译]CSS 居中(Center)方法大合集
  • 3.7、@ResponseBody 和 @RestController
  • Apache的80端口被占用以及访问时报错403
  • Docker: 容器互访的三种方式
  • ECMAScript入门(七)--Module语法
  • electron原来这么简单----打包你的react、VUE桌面应用程序
  • input实现文字超出省略号功能
  • JS创建对象模式及其对象原型链探究(一):Object模式
  • Js实现点击查看全文(类似今日头条、知乎日报效果)
  • MySQL用户中的%到底包不包括localhost?
  • Nodejs和JavaWeb协助开发
  • Protobuf3语言指南
  • Rancher如何对接Ceph-RBD块存储
  • Terraform入门 - 3. 变更基础设施
  • 阿里云前端周刊 - 第 26 期
  • -- 查询加强-- 使用如何where子句进行筛选,% _ like的使用
  • 大快搜索数据爬虫技术实例安装教学篇
  • 等保2.0 | 几维安全发布等保检测、等保加固专版 加速企业等保合规
  • 记一次和乔布斯合作最难忘的经历
  • 聊聊spring cloud的LoadBalancerAutoConfiguration
  • 实现简单的正则表达式引擎
  • 使用API自动生成工具优化前端工作流
  • 算法-插入排序
  • 如何通过报表单元格右键控制报表跳转到不同链接地址 ...
  • ​LeetCode解法汇总518. 零钱兑换 II
  • ​你们这样子,耽误我的工作进度怎么办?
  • #HarmonyOS:基础语法
  • #pragam once 和 #ifndef 预编译头
  • #pragma 指令
  • (二)基于wpr_simulation 的Ros机器人运动控制,gazebo仿真
  • (附源码)springboot社区居家养老互助服务管理平台 毕业设计 062027
  • (机器学习的矩阵)(向量、矩阵与多元线性回归)
  • (免费领源码)Java#ssm#MySQL 创意商城03663-计算机毕业设计项目选题推荐
  • (牛客腾讯思维编程题)编码编码分组打印下标(java 版本+ C版本)
  • (轉貼) VS2005 快捷键 (初級) (.NET) (Visual Studio)
  • .gitignore文件设置了忽略但不生效
  • .NET 2.0中新增的一些TryGet,TryParse等方法
  • .NET Core跨平台微服务学习资源
  • .Net IOC框架入门之一 Unity
  • .NET/C# 中设置当发生某个特定异常时进入断点(不借助 Visual Studio 的纯代码实现)