我之前的博客中有介绍如何在项目中生成额外的代码,也有介绍制作一个生成代码的 NuGet 包。而本文是在此基础上更进一步,可以让生成代码变成实时的;更准确的说,是在保存文件时即生成代码,而无需完整编译一次项目。
一天,头像全白昵称空格的“wuweilai”童鞋问我为什么 GRPC 的 NuGet 包能自动在 .proto 文件保存时更新生成的代码,怎么才能做到像它那样。然后,我研究了下 Grpc.Tools 包里的代码,外加跟他反复讨论,摸清了自动生成代码的方法。
本文的知识非常简单,如果只是希望知道怎么实时生成代码的话,把本文后面的代码复制一下就可以了。但如果希望完整了解基于 MSBuild 生成代码的原理,你可以需要了解以下知识或教程:
我们创建一个全新的项目,用来了解如何实时生成代码。
如下图,就是个普通的控制台应用程序。我额外生成了一个 Test.txt 文件,里面什么也没有。我们即将实现的是:在保存 Test.txt 文件时,会立即执行我们的编译流程,这样,我们便能基于 Test.txt 来实时生成一些代码。
现在,我们打开项目 csproj 文件(双击项目名称即可打开编辑这个文件):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net5.0</TargetFramework> </PropertyGroup> + <!-- 将项目中的所有 txt 文件搜集起来,用 WalterlvDemoFile 集合存起来。--> + <ItemGroup> + <WalterlvDemoFile Include="**\*.txt" Generator="MSBuild:Compile" /> + </ItemGroup> + <!-- 注册 WalterlvDemoFile 项为一个 Item,这样它的通用属性就能被识别了。 --> + <ItemGroup> + <AvailableItemName Include="WalterlvDemoFile" /> + </ItemGroup> + <!-- 随便写一个 Target,在编译之前做些什么。 --> + <Target Name="WalterlvDemoTarget" BeforeTargets="BeforeCompile"> + <Exec Command="winver" /> + </Target> </Project> |
---|
我把新增的代码高亮出来了。如果你想复制到你的项目里,记得去掉行首的所有 +
号。
等你复制到项目里之后,试着在 Test.txt 文件里面随便写点什么,然后保存。你会发现……呃……弹出了一个 Windows 版本号窗口……
WalterlvDemoTarget
(随便取的名字),并要求在 BeforeCompile
这个 Target 执行之前执行。WalterlvDemoFile
项,这是随便取的名字,是为了搜集 *.txt
文件。WalterlvDemoFile
里指定 Generator
为 MSBuild:Compile
。Generator
属性是 MSBuild 编译时的一个已知元数据(Metadata),其作用为当此文件改变时,会执行一个指定的 TargetMSBuild:Compile
,即指定为 MSBuild 内置的一个 Target Compile
,意为执行一次编译WalterlvDemoFile
并不是已知的项,所以我们还需要额外将 WalterlvDemoFile
添加到 AvailableItemName
集合里。WalterlvDemoFile
的 Generator
属性就可以被自动启用了在上面那个最简的 Demo 中,我们弹出了个 Windows 版本号,这真的只是为了让你立刻注意到某个代码执行了。当然真正生成代码肯定不会是这样的弹窗。
不过,你可以从我的其他博客里找到很多生成代码的方法,比如这篇……还有这篇……还有这这这篇……
参考资料
本文会经常更新,请阅读原文: https://blog.walterlv.com/post/msbuild-generate-code-when-file-is-saved.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://blog.walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 ([email protected]) 。