本文整理我和 林德熙 学习的 dotnet 编译知识、Roslyn 源码分析知识,NuGet 知识。通过阅读本文可以从零散的碎片化博客中得到从零开始学习的轨迹。
本文服务于 微软技术暨生态大会 2018 课程,你可以学习预编译框架相关的技术原理。
SourceYard 性能数据
SourceYard 通过将公共组件的源代码和产品源代码合并来提升性能。
以下是这部分的性能数据:
不过,程序集中的类的数量对启动性能没有影响:
SourceFusion 性能数据
SourceFusion 的其中一个用途是收集原本会通过反射收集的类型信息。
以下是这部分的性能数据:
额外的,如果不是收集而单单只是使用的话,这里是性能数据:
dotnet build 基础
你需要先了解 csproj 文件的结构,以便进行后续的学习:
- 理解 C# 项目 csproj 文件格式的本质和编译流程 - 吕毅
- 项目文件中的已知属性(知道了这些,就不会随便在 csproj 中写死常量啦) - 吕毅
- Roslyn 在项目文件使用条件判断 - 林德熙
在了解到 csproj 文件结构之后,你可以通过迁移一些项目,并确保他们编译通过来练习:
- 将 WPF、UWP 以及其他各种类型的旧 csproj 迁移成 Sdk 风格的 csproj - 吕毅
- Sdk 风格的 csproj 对 WPF/UWP 支持不太好?有第三方 SDK 可以用!MSBuild.Sdk.Extras - 吕毅
接着,csproj 中的重要内容 Target 对理解编译过程非常重要,因为它决定了如何编译这个项目:
- Roslyn 如何使用 MSBuild Copy 复制文件 - 林德熙
- 如何使用 MSBuild Target(Exec)中的控制台输出 - 吕毅
- 如何在 MSBuild Target(Exec)中报告编译错误和编译警告 - 吕毅
更高级的 Target 用法:
- 如何编写基于 Microsoft.NET.Sdk 的跨平台的 MSBuild Target(附各种自带的 Task) - 吕毅
- Roslyn 使用 WriteLinesToFile 解决参数过长无法传入 - 林德熙
- 每次都要重新编译?太慢!让跨平台的 MSBuild/dotnet build 的 Target 支持差量编译 - 吕毅
基于 Target 的一些应用:
当现有的知识和文档不足以帮助你完成现有功能的时候,也许你该考虑阅读官方源码了:
- 解读 Microsoft.NET.Sdk 的源码,你能定制各种奇怪而富有创意的编译过程 - 吕毅
- Reading the Source Code of Microsoft.NET.Sdk, Writing the Creative Extension of Compiling - 吕毅
还有一些 csproj 特性的使用:
- .NET/C# 中你可以在代码中写多个 Main 函数,然后按需要随时切换 - 吕毅
- 在 Visual Studio 的解决方案资源管理器中隐藏一些文件 - 吕毅
- 使用链接共享 Visual Studio 中的代码文件 - 吕毅
- 为 Visual Studio 使用通配符批量添加项目文件 - 吕毅
- Roslyn 使用 Directory.Build.props 管理多个项目配置 - 林德熙
- Roslyn 使用 Directory.Build.props 文件定义编译 - 林德熙
- 使用 MSBuild 响应文件 (rsp) 来指定 dotnet build 命令行编译时的大量参数 - 吕毅
NuGet 基础
可以使用 NuGet 做一些不是传统 dll 引用的功能:
现在,我们需要真的使用 NuGet 做一个自己的工具了:
- 如何创建一个基于 MSBuild Task 的跨平台的 NuGet 工具包 - 吕毅
- 如何创建一个基于命令行工具的跨平台的 NuGet 工具包 - 吕毅
- 在制作跨平台的 NuGet 工具包时,如何将工具(exe/dll)的所有依赖一并放入包中 - 吕毅
NuGet 的坑很多,有些可以解,有些需要规避:
- 帮助官方 NuGet 解掉 Bug,制作绝对不会传递依赖的 NuGet 包 - 吕毅
- MSBuild/Roslyn 和 NuGet 的 100 个坑 - 吕毅
- Roslyn 通过 Nuget 引用源代码 在 VS 智能提示正常但是无法编译 - 林德熙
如果你的 NuGet 格式是旧的,或者说引用方式是旧的,推荐升级:
- 自动将 NuGet 包的引用方式从 packages.config 升级为 PackageReference - 吕毅
- 如何最快速地将旧的 NuGet 包 (2.x, packages.config) 升级成新的 NuGet 包 (4.x, PackageReference) - 吕毅
学会这些 NuGet 技能之后的一些应用:
SourceYard 原理
SourceYard 利用 NuGet 自动 Import 的 Target 来执行我们的代码:
- Roslyn 使用 Target 替换占位符方式生成 nuget 打包 - 林德熙
- Roslyn 通过 Target 修改编译的文件 - 林德熙
- 将 .NET Core 项目打一个最简单的 NuGet 源码包,安装此包就像直接把源码放进项目一样 - 吕毅
- Roslyn 如何基于 Microsoft.NET.Sdk 制作源代码包 - 林德熙
Roslyn 基础
Roslyn 由于其丰富且易用的 API,所以入门是比较容易的。推荐的入门文章有:
- Roslyn 入门:使用 Visual Studio 的语法可视化(Syntax Visualizer)窗格查看和了解代码的语法树 - 吕毅
- Roslyn 静态分析 - 林德熙
- Roslyn 入门:使用 Roslyn 静态分析现有项目中的代码 - 吕毅
- Roslyn 入门:使用 .NET Core 版本的 Roslyn 编译并执行跨平台的静态的源码 - 吕毅
额外的,你可以阅读更多 Roslyn 的资料以便快速应用于你的项目:
- Roslyn 语法树中的各种语法节点及每个节点的含义 - 吕毅
- Roslyn 节点的 Span 和 FullSpan 有什么区别 - 林德熙
- Roslyn NameSyntax 的 ToString 和 ToFullString 的区别 - 林德熙
Roslyn 为何能够在提供如此友好的 API 的情况下依然有如此高的性能?
一些 Roslyn 的额外功能:
SourceFusion 预编译框架
关于预编译框架的博客没有那么多,只有一些基本的使用:
扩展阅读
这里是是用到了 csproj / NuGet 等的额外博客:
- 语义版本号(Semantic Versioning) - 吕毅
- (1/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序 - 吕毅
- dotnet core 通过修改文件头的方式隐藏控制台窗口 - 林德熙
- 使用 GitVersion 在编译或持续构建时自动使用语义版本号(Semantic Versioning) - 吕毅
- Automatically increase the semantic version using GitVersion - 吕毅
本文会经常更新,请阅读原文: https://blog.walterlv.com/post/posts-for-learning-dotnet-build-nuget-roslyn.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://blog.walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 ([email protected]) 。