6

编写你的专属 MSBuild C# 代码生成器:在保存文件时自动实时生成你的代码

 3 years ago
source link: https://blog.walterlv.com/post/msbuild-generate-code-when-file-is-saved.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

编写你的专属 MSBuild C# 代码生成器:在保存文件时自动实时生成你的代码

2021-06-01 12:34

我之前的博客中有介绍如何在项目中生成额外的代码,也有介绍制作一个生成代码的 NuGet 包。而本文是在此基础上更进一步,可以让生成代码变成实时的;更准确的说,是在保存文件时即生成代码,而无需完整编译一次项目。


一天,头像全白昵称空格的“wuweilai”童鞋问我为什么 GRPC 的 NuGet 包能自动在 .proto 文件保存时更新生成的代码,怎么才能做到像它那样。然后,我研究了下 Grpc.Tools 包里的代码,外加跟他反复讨论,摸清了自动生成代码的方法。

本文的知识非常简单,如果只是希望知道怎么实时生成代码的话,把本文后面的代码复制一下就可以了。但如果希望完整了解基于 MSBuild 生成代码的原理,你可以需要了解以下知识或教程:

我们创建一个全新的项目,用来了解如何实时生成代码。

如下图,就是个普通的控制台应用程序。我额外生成了一个 Test.txt 文件,里面什么也没有。我们即将实现的是:在保存 Test.txt 文件时,会立即执行我们的编译流程,这样,我们便能基于 Test.txt 来实时生成一些代码。

一个简单的项目结构

最简单的自动生成代码的逻辑

现在,我们打开项目 csproj 文件(双击项目名称即可打开编辑这个文件):

  <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 版本号窗口……

最简代码解读

  1. 我们定义了一个 Target,名为 WalterlvDemoTarget(随便取的名字),并要求在 BeforeCompile 这个 Target 执行之前执行。
  2. 我们定义了一个 WalterlvDemoFile 项,这是随便取的名字,是为了搜集 *.txt 文件。
  3. 我们在 WalterlvDemoFile 里指定 GeneratorMSBuild:Compile
    • 对于已知的项(Item)来说,Generator 属性是 MSBuild 编译时的一个已知元数据(Metadata),其作用为当此文件改变时,会执行一个指定的 Target
    • 我们将其指定为 MSBuild:Compile,即指定为 MSBuild 内置的一个 Target Compile,意为执行一次编译
  4. 然而,WalterlvDemoFile 并不是已知的项,所以我们还需要额外将 WalterlvDemoFile 添加到 AvailableItemName 集合里。

在上面那个最简的 Demo 中,我们弹出了个 Windows 版本号,这真的只是为了让你立刻注意到某个代码执行了。当然真正生成代码肯定不会是这样的弹窗。

不过,你可以从我的其他博客里找到很多生成代码的方法,比如这篇……还有这篇……还有这这这篇……


参考资料

本文会经常更新,请阅读原文: https://blog.walterlv.com/post/msbuild-generate-code-when-file-is-saved.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

如果你想持续阅读我的最新博客,请点击 RSS 订阅,或者前往 CSDN 关注我的主页

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK