dotnet 源代码生成器分析器入门

张春  金牌会员 | 2025-3-22 18:47:44 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 976|帖子 976|积分 2928

本文将带领大家入门 dotnet 的 SourceGenerator 源代码生成器技术,期待大家阅读完本文能够看懂理解和编写源代码生成器和分析器
恭喜你看到了本文,进入到 C# dotnet 的深水区。如果你还是在浅水玩耍的小鲜肉,推荐你点击右上方的关闭按钮,避免受到过于深入的知识的污染
我所在的团队在 Rosyln 刚出来没两年就开始玩了,那时候还没有现在这么多机制。我之前很多关于 Rosyln 的博客都涉及到了很底层的玩法,导致入门门槛过高。随着 dotnet 生态的不断建立,渐渐有了源代码生成技术、增量源代码生成技术等等。这次我计划综合之前的经验和知识,根据现在的 dotnet 的生态技术,编写这篇入门博客,让大家更好地入门源代码生成器和分析器,降低入门门槛。本文将尽量使用比力缓的知识爬坡方式编写,以便让大家更舒适地进入到源代码生成器和分析器的世界
在开始之前盼望大家已经了解基础的 dotnet C# 基础知识,了解基础的概念和项目组织结构
在阅读本文过程中,发现本文有任何错误或不敷之处,欢迎大家在评论区留言或发送邮件给我,我会尽快修正。如果大家有任何问题或疑问,也欢迎大家在评论区留言或发送邮件给我,我会尽快回复
本文内容比力长,知识量比力多,推荐先点收藏
项目搭建

本文先从项目搭建开始告诉大家如何创建一个源代码生成器项目。本文后续的内容将会在这个项目中举行演示。本文的编写顺序是先搭建项目,然后再讲解一些基础的概念和用法,再到如何举行调试,最后提供一些实际的演练给到大家。基础知识部分也放在演练里面,先做演练再讲基础知识,防止一口气拍出大量基础知识劝退大家
本文的推荐打开方式是一边阅读本文,一边打开 Visual Studio 2022 或更高版本,对照本文的内容举行操作。照着本文的内容对照着编写代码,可以让大家更好地理解本文的内容,照着过一遍预计就能掌握基础的源代码生成器和分析器的知识,入门源代码生成器和分析器的编写
本文过程中会添加一些外部链接文档,这些外部链接文档都是可选阅读内容,只供大家感爱好时扩展阅读。本文的焦点内容是在本文中编写的,不必要阅读外部链接文档也能够掌握本文的内容。作为入门博客,我担心本身编写过程中存在高手盲区问题,于是尽可能将更多细节写出来,尽管这样会导致一些重复的表述
先新建一个控制台项目,新建完成之后在 Visual Studio 2022 或更高版本中打开项目,双击 csproj 项目文件,即可举行编辑项目文件
本文这里新建了一个名为 DercelgefarKarhelchaye.Analyzer 的控制台项目。也许细心的伙伴发现了这个项目使用了 Analyzer 作为后缀,这是因为在 dotnet 中源代码生成器和分析器是一体的,按照历史缘故原由的惯性,依然将其定名为分析器项目。在 Visual Studio 2022 的每个项目依靠项里面,大家都会看到如下图的一个名为分析器的项,而没有专门一个名为源代码生成器的项,其缘故原由也是如此

如果在这一步就开始卡住了也不用慌,本文在整个过程中都会给出示例代码。我整个代码堆栈比力庞大,使用本文各个部分提供的拉取源代码的命令行代码,可以减少拉取的数据,提升拉取的速率,且能够确保切换到精确的 commit 代码
创建之后,在 Visual Studio 的办理方案里的界面大概如下

编辑名为 DercelgefarKarhelchaye.Analyzer 的控制台项目标 csproj 项目文件,将其 TargetFramework 降级到 netstandard2.0 版本,且按照 dotnet 的惯例,使用 NuGet 添加必要的组件。编辑之后的 csproj 项目文件的内容如下
  1. <Project Sdk="Microsoft.NET.Sdk">
  2.   <PropertyGroup>
  3.     <TargetFramework>netstandard2.0</TargetFramework>
  4.     <LangVersion>latest</LangVersion>
  5.     <EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
  6.   </PropertyGroup>
  7.   <ItemGroup>
  8.     <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" PrivateAssets="all" />
  9.     <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.12.0" PrivateAssets="all" />
  10.   </ItemGroup>
  11. </Project>
复制代码
为什么必要降级为 netstandard2.0 版本?这是为了让此分析器项目能够同时在 dotnet CLI 和 Visual Studio 2022 里面使用。在 Visual Studio 2022 里,当前依然使用的是 .NET Framework 的版本。于是求最小公倍数,选择了 netstandard2.0 版本。预计后续版本才能使用到最新的 dotnet 框架版本
以上的 latest 只是为了方便让咱使用最新的语言特性。前面选择的 netstandard2.0 会导致语言特性默认开得比力低,这里设置为 latest 可以让我们使用最新的语言特性,让代码编写更加方便。这里必要再次提醒,在 dotnet 里面,语言和框架是分开的。使用低版本框架也能使用高版本语言。如果对语言和框架的关系依然有所迷惑,推荐先了解一下 dotnet 的基础知识,不要着急往下看。编写源代码生成器和分析器必要对 dotnet 有一定的了解,否则写着就开始混淆概念了
以上的 true 的作用是强制实行扩展分析器规则。这个属性是为了让我们在编写分析器的时候能够更加严格,让我们的代码更加规范。这里大家不必要细致了解,如有爱好,请参阅 Roslyn 分析器 EnforceExtendedAnalyzerRules 属性的作用
以上的 Microsoft.CodeAnalysis.Analyzers 和 Microsoft.CodeAnalysis.CSharp 是必须的组件。Microsoft.CodeAnalysis.Analyzers 是分析器的基础组件,Microsoft.CodeAnalysis.CSharp 是 C# 的基础组件。这两个组件是必须的,没有这两个组件,我们就无法编写分析器和源代码生成器
通过以上的步调也可以让大家看到,实在 dotnet 分析器项目也没什么特殊的,依然可以通过一个简单的控制台项目修改而来。其焦点关键仅仅只是安装了 Microsoft.CodeAnalysis.Analyzers 和 Microsoft.CodeAnalysis.CSharp 两个组件而已

现在只是有了一个空的分析器项目,但是还不知道这个项目标结果。为了让分析器项目工作,那就必要有一个被分析的项目。为此咱就再次新建一个控制台项目,让这个控制台项目成为被分析项目
我这里新建了一个名为 DercelgefarKarhelchaye 的控制台项目。编辑 DercelgefarKarhelchaye 的 csproj 项目文件,让其引用 DercelgefarKarhelchaye.Analyzer 项目,且设置 DercelgefarKarhelchaye.Analyzer 为分析器。编辑之后的 csproj 项目文件的内容如下
  1. <Project Sdk="Microsoft.NET.Sdk">
  2.   <PropertyGroup>
  3.     <OutputType>Exe</OutputType>
  4.     <TargetFramework>net9.0</TargetFramework>
  5.     <ImplicitUsings>enable</ImplicitUsings>
  6.     <Nullable>enable</Nullable>
  7.   </PropertyGroup>
  8.   <ItemGroup>
  9.     <ProjectReference Include="..\DercelgefarKarhelchaye.Analyzer\DercelgefarKarhelchaye.Analyzer.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
  10.   </ItemGroup>
  11. </Project>
复制代码
可以看到以上的 csproj 项目文件和正常的控制台项目标差别仅仅只有在对 DercelgefarKarhelchaye.Analyzer.csproj 的引用上。且和正常的引用项目标方式不同的是,这里额外添加了 OutputItemType="Analyzer" ReferenceOutputAssembly="false" 两个配置。这两个配置的作用如下:

  • 以上的 OutputItemType="Analyzer" 是告诉 dotnet 这个引用项目是一个分析器项目。这个配置是必须的,没有这个配置,dotnet 就不知道这个项目是一个分析器项目。通过这个配置是告诉 dotnet 这个项目是一个分析器项目,才能让 dotnet 在编译的时候能够精确地当成分析器处置惩罚这个项目
  • 以上的 ReferenceOutputAssembly="false" 是告诉 dotnet 不要引用这个项目标输出程序集。正常的项目是不应该引用分析器项目标程序集的,分析器项目标作用仅仅只是作为分析器,而不是提供程序集给其他项目引用。这个配置是为了让 dotnet 在编译的时候不要引用这个项目标输出程序集,避免引用错误或导致不小心用了不应该使用的类型
对于正常的项目引用来说,一旦存在项目引用,那被引用的项目标输出程序集就会被引用。此时项目上就可以使用被引用项目标公开类型,以及获取 NuGet 包依靠传递等。但是对于分析器项目来说,这些都是不应该的,正常就不能让项目引用分析器项目标输出程序集。这就是为什么会额外添加 ReferenceOutputAssembly="false" 配置的缘故原由

在这里,咱打仗到了非常多次的 csproj 项目文件,如果大家对 csproj 项目文件格式感爱好,请参阅 理解 C# 项目 csproj 文件格式的本质和编译流程 - walterlv
以上的步调完成之后,最简单的分析器项目和被分析的项目就搭建完成了。这也是分析器的基础,大部分的带分析器的代码都是如此方式搭建的。但也有其他部分是通过 NuGet 带出去的分析器,被 NuGet 带出去的分析器能够更好做到开箱即用,不必要让分析器尝试构建。在后文将会讲解如何将分析器通过 NuGet 带出去,即如何举行分发分析器
现在的分析器项目还没有任何源代码生成和分析的功能,接下来咱将编写简单的源代码生成的代码,让大家看到源代码生成器的结果
编写源代码生成器

在 DercelgefarKarhelchaye.Analyzer 项目中新建一个名为 IncrementalGenerator 的源代码生成器类。编辑 IncrementalGenerator 类,让其继承 IIncrementalGenerator 接口,实现 Initialize 方法,且标志 [Generator(LanguageNames.CSharp)] 特性。编辑之后的 HelloWorldGenerator 类的内容如下
  1. using Microsoft.CodeAnalysis;
  2. namespace DercelgefarKarhelchaye.Analyzer;
  3. [Generator(LanguageNames.CSharp)]
  4. public class IncrementalGenerator : IIncrementalGenerator
  5. {
  6.     public void Initialize(IncrementalGeneratorInitializationContext context)
  7.     {
  8.   <ItemGroup>
  9.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  10.   </ItemGroup>... // 忽略其他代码
  11.     }
  12. }
复制代码
本文这里直接就是和大家介绍 IIncrementalGenerator 增量 Source Generator 源代码生成器技术,不再介绍 ISourceGenerator 源代码生成器技术。其缘故原由是在 2022 之后,官方大力推荐的是使用 IIncrementalGenerator 增量源代码生成器技术。从业务上讲,仅仅只是 IIncrementalGenerator 多了增量的功能,在举行源代码生成逻辑处置惩罚中没有太大的差别。功能上 IIncrementalGenerator 也能完全代替 ISourceGenerator 的功能。但是在性能上,IIncrementalGenerator 要比 ISourceGenerator 更加高效,更加快速,更加能够防止原本已经很卡的 Visual Studio 更加卡
整个 IIncrementalGenerator 的入口都在 Initialize 方法里面,从 IncrementalGeneratorInitializationContext 参数里可以点出来非常多有用的方法。咱这里先不展开讲解这些方法,先让大家看到一个简单的源代码生成器的结果
在 Initialize 方法里面,咱可以通过 context.RegisterPostInitializationOutput 方法注册一个源代码输出。如以下代码所示,将输出一个名为 GeneratedCode 的代码
  1.     public void Initialize(IncrementalGeneratorInitializationContext context)
  2.     {
  3.   <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>context.RegisterPostInitializationOutput(initializationContext =>
  6.   <ItemGroup>
  7.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  8.   </ItemGroup>{
  9.   <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>    initializationContext.AddSource("GeneratedCode.cs",
  12.   <ItemGroup>
  13.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  14.   </ItemGroup>  <ItemGroup>
  15.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  16.   </ItemGroup>"""
  17.   <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>using System;
  22.   <ItemGroup>
  23.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  24.   </ItemGroup>  <ItemGroup>
  25.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  26.   </ItemGroup>namespace DercelgefarKarhelchaye
  27.   <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>  <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>{
  32.   <ItemGroup>
  33.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  34.   </ItemGroup>  <ItemGroup>
  35.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  36.   </ItemGroup>    public static class GeneratedCode
  37.   <ItemGroup>
  38.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  39.   </ItemGroup>  <ItemGroup>
  40.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  41.   </ItemGroup>    {
  42.   <ItemGroup>
  43.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  44.   </ItemGroup>  <ItemGroup>
  45.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  46.   </ItemGroup>  <ItemGroup>
  47.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  48.   </ItemGroup>public static void Print()
  49.   <ItemGroup>
  50.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  51.   </ItemGroup>  <ItemGroup>
  52.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  53.   </ItemGroup>  <ItemGroup>
  54.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  55.   </ItemGroup>{
  56.   <ItemGroup>
  57.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  58.   </ItemGroup>  <ItemGroup>
  59.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  60.   </ItemGroup>  <ItemGroup>
  61.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  62.   </ItemGroup>    Console.WriteLine("Hello from generated code!");
  63.   <ItemGroup>
  64.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  65.   </ItemGroup>  <ItemGroup>
  66.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  67.   </ItemGroup>  <ItemGroup>
  68.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  69.   </ItemGroup>}
  70.   <ItemGroup>
  71.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  72.   </ItemGroup>  <ItemGroup>
  73.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  74.   </ItemGroup>    }
  75.   <ItemGroup>
  76.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  77.   </ItemGroup>  <ItemGroup>
  78.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  79.   </ItemGroup>}
  80.   <ItemGroup>
  81.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  82.   </ItemGroup>  <ItemGroup>
  83.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  84.   </ItemGroup>""");
  85.   <ItemGroup>
  86.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  87.   </ItemGroup>});
  88.     }
复制代码
预期此时能够将生成的 GeneratedCode 类型注入到被分析的项目中。在被分析的项目中,可以通过 GeneratedCode.Print() 方法输出 Hello from generated code! 字符串
好的,进入到 DercelgefarKarhelchaye 项目中,编辑 Program 类,调用 GeneratedCode.Print() 方法。编辑之后的 Program 类的内容如下
  1. using DercelgefarKarhelchaye;
  2. GeneratedCode.Print();
复制代码
尝试运行一下 DercelgefarKarhelchaye 项目,可以看到控制台输出了 Hello from generated code! 字符串。这就是源代码生成器的结果,通过源代码生成器生成的代码,注入到被分析的项目中,让被分析的项目能够使用生成的代码
如此证实白在 DercelgefarKarhelchaye.Analyzer 分析器项目中编写的源代码生成器生效了。这就是源代码生成器的基硋,通过源代码生成器生成的代码,注入到被分析的项目中,让被分析的项目能够使用生成的代码
以上代码放在 githubgitee 上,可以使用如下命令行拉取代码。我整个代码堆栈比力庞大,使用以下命令行可以举行部分拉取,拉取速率比力快
先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
  1. git init
  2. git remote add origin https://gitee.com/lindexi/lindexi_gd.git
  3. git pull origin 95c14524130238b2d6fbca97ca35b89dc921536b
复制代码
以上使用的是国内的 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继承输入以下代码,将 gitee 源换成 github 源举行拉取代码。如果依然拉取不到代码,可以发邮件向我要代码
  1. git remote remove origin
  2. git remote add origin https://github.com/lindexi/lindexi_gd.git
  3. git pull origin 95c14524130238b2d6fbca97ca35b89dc921536b
复制代码
获取代码之后,进入 Roslyn/DercelgefarKarhelchaye 文件夹,即可获取到源代码
分析和生成入门

在上文中,和大家介绍了如何生成静态的固定的代码内容。在 RegisterPostInitializationOutput 方法里面,只答应传递静态固定的代码,不能依据当前项目状态或配置举举措态生成代码。这是因为 RegisterPostInitializationOutput 方法的界说上就是用于提供分析器开始分析工作之前的初始化代码。这部分代码由于可不用运行分析过程,可以非常快给到 IDE 层,一般用于提供一些类型界说,可以给到开发者直接快速使用,而不会在使用过程中飘红
上文的代码只是让大家粗略熟悉了一下 IIncrementalGenerator 的 API 调用方法。接下来我将带大家开始入门分析器的分析和生成功能
分析和生成很多时候都是不分离的,生成的代码必要依靠分析的结果。为了能让大家更好理解分析器的入门知识,我尝试部署一个任务,接下来让咱根据部署的任务来入门分析和生成功能
任务

咱来实现一个经典的需求任务,将项目里面的标志了某个 Attribute 特性的类型全收集起来,最后生成一个代码,让生成的代码输出有哪些类型标志了这个 Attribute 特性,将这些类型的名称输出到控制台
进一步分解任务需求,咱必要有一个源代码生成器。源代码生成器生成两部分代码,第一部分就是 FooAttribute 特性,第二部分就是收集所有标志了 FooAttribute 特性的类型,生成将这些类型的名称输出到控制台的代码。要求全程没有反射参与,全程都是通过 Roslyn 分析和生成完成
使用 ForAttributeWithMetadataName 快速分析代码

从工程上举行分析发现,非常大量的分析生成任务都有一个特点,这个特点就是必要找到标志了某个 Attribute 特性的类型或方法或属性等,然后再做某个事情。这个特点实在源自于 dotnet C# 对于 Attribute 特性的计划。Attribute 特性是一种元数据,可以标志在类型、方法、属性等上面,用于描述这个类型、方法、属性等的特性。也经常用于标志给 IDE 和编译器看的,用于告诉 IDE 和编译器这个类型、方法、属性等的特性。比如常用的 ObsoleteAttribute 、CallerMemberNameAttribute 、DebuggerDisplayAttribute 等等
在 IIncrementalGenerator 增量 Source Generator 源代码生成器中,提供了 ForAttributeWithMetadataName 工具方法。如此方法名所述,这个方法是用于找到标志了某个 Attribute 特性的类型、方法、属性等。这个方法的使用非常简单,只必要传递一个 Attribute 特性的完整名称,就可以找到标志了这个 Attribute 特性的类型、方法、属性等
在上文的任务中,咱必要找到标志了某个 Attribute 特性的类型,然后将这些类型的名称输出到控制台。这个任务非常适合使用 ForAttributeWithMetadataName 方法来实现。接下来咱就来实现这个任务
依然是新建两个项目,其中一个作为分析器项目,另一个作为被分析的项目。大家既可以在上文现有的项目中继承编写,也可以新建两个项目。这里我新建了一个名为 NinahajawhuLairfoheahurcee.Analyzer 的分析器项目,和一个名为 NinahajawhuLairfoheahurcee 的被分析项目。本文内容里面只给出关键代码片段,如必要全部的项目文件,可在下文找到所有代码的下载方法。如果本身编写的代码构建不通过或运行输出不符合预期,也推荐大家拉取本文的代码举行阅读
先来完成任务需求分解中的第一部分,编写 FooAttribute 特性代码的生成。由于 FooAttribute 特性的代码不依靠任何分析结果,因此可以使用 RegisterPostInitializationOutput 方法生成。修改上文的 RegisterPostInitializationOutput 注册 GeneratedCode.cs 的代码,将其替换为 FooAttribute.cs 的生成代码,如下所示
  1. [Generator(LanguageNames.CSharp)]
  2. public class IncrementalGenerator : IIncrementalGenerator
  3. {
  4.     public void Initialize(IncrementalGeneratorInitializationContext context)
  5.     {
  6.   <ItemGroup>
  7.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  8.   </ItemGroup>// 先注册一个特性给到业务方使用
  9.   <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>context.RegisterPostInitializationOutput(initializationContext =>
  12.   <ItemGroup>
  13.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  14.   </ItemGroup>{
  15.   <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>    initializationContext.AddSource("FooAttribute.cs",
  18.   <ItemGroup>
  19.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  20.   </ItemGroup>  <ItemGroup>
  21.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  22.   </ItemGroup>"""
  23.   <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>namespace Lindexi;
  28.   <ItemGroup>
  29.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  30.   </ItemGroup>  <ItemGroup>
  31.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  32.   </ItemGroup>public class FooAttribute : Attribute
  33.   <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>  <ItemGroup>
  36.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  37.   </ItemGroup>{
  38.   <ItemGroup>
  39.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  40.   </ItemGroup>  <ItemGroup>
  41.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  42.   </ItemGroup>}
  43.   <ItemGroup>
  44.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  45.   </ItemGroup>  <ItemGroup>
  46.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  47.   </ItemGroup>""");
  48.   <ItemGroup>
  49.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  50.   </ItemGroup>});
  51.     }
  52. }
复制代码
完成这一步之后,即可在业务端编写类型,将类型标志上 FooAttribute 特性。回到名为 NinahajawhuLairfoheahurcee 的被分析项目,在 NinahajawhuLairfoheahurcee 控制台项目里面添加两个类型,让这两个类型标志上 FooAttribute 特性,用于后续测试类型被收集
  1. using Lindexi;
  2. namespace NinahajawhuLairfoheahurcee;
  3. [Foo]
  4. public class F1
  5. {
  6. }
  7. [Foo]
  8. public class F2
  9. {
  10. }
复制代码
在 IIncrementalGenerator 增量 Source Generator 源代码生成,可在 IncrementalGeneratorInitializationContext 里面的 SyntaxProvider 属性,通过 ForAttributeWithMetadataName 快速收集标志了某个特性的类型、属性、方法等等
基本写法格式如下
  1. var provider =
  2.     context.SyntaxProvider.ForAttributeWithMetadataName
  3.     (
  4.   <ItemGroup>
  5.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  6.   </ItemGroup>"特性名",
  7.   <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>(SyntaxNode node, CancellationToken token) => 语法判断条件,
  10.   <ItemGroup>
  11.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  12.   </ItemGroup>(GeneratorAttributeSyntaxContext syntaxContext, CancellationToken token) => 语义处理和获取返回值
  13.     );
复制代码
第一个参数是特性名,记得带上特性的定名空间,以及写明特性的全名。在正常的 C# 代码里面,都会忽略 Attribute 后缀,但是在这里必要带上 Attribute 后缀。第二个参数是语法判断条件,用于判断当前节点是否符合条件。第三个参数是语义处置惩罚和获取返回值,用于处置惩罚当前节点的语义,获取返回值
那什么是语法,什么是语义呢? 在 Roslyn 里面,将初步的代码分析的语法层面内容称为 Syntax 语法。语法是非常贴近编写出来的代码直接的内存映射的样子,这个过程里面只做片面考虑,即不考虑代码之间的引用关系,只考虑代码语法本身。语法分析过程是最早的过程,也是损耗极小的过程,也是可以并行化实行的过程。一般来说,举行语法分析都可以将写出来的代码分为一个个 SyntaxTree 语法树,每个代码或代码片都可以转换为一个 SyntaxNode 语法节点
对应于 Syntax 语法的概念,语义 Semantic 则是包罗了代码的寄义,不但仅只是语法层面上,语义 Semantic 包罗了代码之间的引用关系,包罗了各个符号的信息。语义分析过程是在语法分析之后的过程,实行过程中有所损耗,且存在多个代码文件和程序集之间的引用关联关系,这就是为什么在 IIncrementalGenerator 增量 Source Generator 源代码生成计划中是先做语法分析,判断结果通过,再做语义分析的缘故原由
再简单理解可以是如 C# 里面有分部类的概念,举行语法分析的时候,只能一次一个文件一个文件的分析,难以或无法直接分部类的其他分部在哪。但是举行语义分析的时候,可以将所有分部类的信息都收集起来,然后再举行分析,这样就能够找到所有分部类的信息。且在语义分析过程中,能够非常明白知道某个符号的确切寄义
语法和语义有比力庞大的知识,我将在后文的专门章节里面详细介绍。这里只是让大家粗略了解一下语法和语义的概念,以便大家能够更好理解后续的内容。本章内容也不会涉及多少的语法和语义知识,不必要对语法和语义有太多的了解,只必要知道这两个概念的存在即可
粗略了解了一点语法和语义的概念,接下来咱就来实现 ForAttributeWithMetadataName 方法的使用。在 NinahajawhuLairfoheahurcee.Analyzer 分析器项目中,修改 IncrementalGenerator 类的 Initialize 方法,添加 ForAttributeWithMetadataName 方法的使用,如下所示
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>IncrementalValuesProvider<string> targetClassNameProvider = context.SyntaxProvider.ForAttributeWithMetadataName("Lindexi.FooAttribute",
  4.   <ItemGroup>
  5.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  6.   </ItemGroup>    // 进一步判断
  7.   <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>    (SyntaxNode node, CancellationToken token) => node.IsKind(SyntaxKind.ClassDeclaration),
  10.   <ItemGroup>
  11.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  12.   </ItemGroup>    (GeneratorAttributeSyntaxContext syntaxContext, CancellationToken token) => syntaxContext.TargetSymbol.Name);
复制代码
如上面代码所示,第一个参数传入特性名,即 "Lindexi.FooAttribute" 字符串。此时将进入预设逻辑,增量的寻找所有标志了名为 "Lindexi.FooAttribute" 特性的类型或属性或方法等等代码。一旦找到了标志了 "Lindexi.FooAttribute" 特性的代码,将会进入第二个参数的语法判断条件,即 (SyntaxNode node, CancellationToken token) => node.IsKind(SyntaxKind.ClassDeclaration) 代码块。此时将进入进一步判断,只有当找到的代码是类声明的时候,才是符合咱的任务需求的代码,即满足感爱好的条件。这里的 SyntaxNode.IsKind 方法是判断当前传入的 SyntaxNode 是什么。前面步调只是找到了标志了 "Lindexi.FooAttribute" 特性的代码,这里进一步判断找到的代码是不是类声明。满足前两个步调,则证实这是一个在类型上面标志了名为 "Lindexi.FooAttribute" 特性的代码,可以进入最后一个参数里面举行进一步的语义处置惩罚
进一步的语义处置惩罚是 (GeneratorAttributeSyntaxContext syntaxContext, CancellationToken token) => syntaxContext.TargetSymbol.Name 代码块。这里的 GeneratorAttributeSyntaxContext.TargetSymbol 属性是当前找到的代码的符号,即当前找到的代码的语义信息。这里的 TargetSymbol.Name 属性是当前找到的代码的名称,即当前找到的代码的类型名称。这里的代码块返回的是当前找到的代码的类型名称,即当前找到的代码的名称
将其返回的内容是类似 Linq 的查询结果,即 IncrementalValuesProvider 类型。这个类型是一个增量的值提供者,而不是立即就返回一次所有满足条件的代码。在 Visual Studio 里面的实行逻辑上,大家可以以为是每更改、新增一次代码,就会实行一次这个查询逻辑,整个查询逻辑是源源不断实行的,不是一次性的,也不是瞬时全跑的,而是增量的逐步实行的
实行过程也是一级级实行的,先通过了第一个参数的特性名,快速判断是否满足参数条件,再颠末第二个参数举行语法判断。颠末前面两个参数判断就可以快速过滤掉大量的代码,如此的方式可以极大减少计算工作量
现在拿到了 IncrementalValuesProvider 返回值,能够从这里源源不断取出一个个类型出来。但按照咱的任务需求,咱是必要一口气收集所有类型的,不能一个个慢慢取。为此咱必要将 IncrementalValuesProvider 给收集起来,成为一个集合数组。这里可以使用 Collect 方法举行收集,如下所示
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>IncrementalValueProvider<ImmutableArray<string>> targetClassNameArrayProvider = targetClassNameProvider
  4.   <ItemGroup>
  5.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  6.   </ItemGroup>    .Collect();
复制代码
可以看到此时返回值就从 IncrementalValuesProvider 类型转换为 IncrementalValueProvider 类型。焦点不同在于 string 和 ImmutableArray 不可变数组的差异而已。在整个 Roslyn 计划里面,大量采用不可变思想,这里的返回值就是不可变思想的一个体现。细心的伙伴可以看到 IncrementalValuesProvider 和 IncrementalValueProvider 这两个单词的差别,没错,焦点在于 Values 和 Value 的差别。在增量源代码生成器里面,使用 IncrementalValuesProvider 表示多值提供器,使用 IncrementalValueProvider 表示单值提供器,两者差异只是值提供器里面提供的数据是多项还是单项。使用 Collect 方法可以将一个多值提供器的内容收集起来,收集为一个不可变集合,从而转换为一个单值提供器,这个单值提供器里面只有一项,且这一项是一个不可变数组。这部分细节内容将在下文和大家详细介绍,在本章节里面就不过多描述
最后一步就是将 IncrementalValueProvider 返回值注册到输出源代码中。在 IncrementalGenerator 类的 Initialize 方法里面,使用 context.RegisterSourceOutput 方法注册输出源代码,如下所示
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>context.RegisterSourceOutput(targetClassNameArrayProvider, (productionContext, classNameArray) =>
  4.   <ItemGroup>
  5.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  6.   </ItemGroup>{
  7.   <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>    productionContext.AddSource("GeneratedCode.cs",
  10.   <ItemGroup>
  11.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  12.   </ItemGroup>  <ItemGroup>
  13.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  14.   </ItemGroup>$$"""
  15.   <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>using System;
  20.   <ItemGroup>
  21.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  22.   </ItemGroup>  <ItemGroup>
  23.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  24.   </ItemGroup>namespace NinahajawhuLairfoheahurcee
  25.   <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>{
  30.   <ItemGroup>
  31.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  32.   </ItemGroup>  <ItemGroup>
  33.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  34.   </ItemGroup>    public static class GeneratedCode
  35.   <ItemGroup>
  36.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  37.   </ItemGroup>  <ItemGroup>
  38.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  39.   </ItemGroup>    {
  40.   <ItemGroup>
  41.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  42.   </ItemGroup>  <ItemGroup>
  43.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  44.   </ItemGroup>  <ItemGroup>
  45.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  46.   </ItemGroup>public static void Print()
  47.   <ItemGroup>
  48.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  49.   </ItemGroup>  <ItemGroup>
  50.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  51.   </ItemGroup>  <ItemGroup>
  52.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  53.   </ItemGroup>{
  54.   <ItemGroup>
  55.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  56.   </ItemGroup>  <ItemGroup>
  57.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  58.   </ItemGroup>  <ItemGroup>
  59.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  60.   </ItemGroup>    Console.WriteLine("标记了 Foo 特性的类型有: {{string.Join(",", classNameArray)}}");
  61.   <ItemGroup>
  62.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  63.   </ItemGroup>  <ItemGroup>
  64.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  65.   </ItemGroup>  <ItemGroup>
  66.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  67.   </ItemGroup>}
  68.   <ItemGroup>
  69.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  70.   </ItemGroup>  <ItemGroup>
  71.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  72.   </ItemGroup>    }
  73.   <ItemGroup>
  74.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  75.   </ItemGroup>  <ItemGroup>
  76.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  77.   </ItemGroup>}
  78.   <ItemGroup>
  79.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  80.   </ItemGroup>  <ItemGroup>
  81.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  82.   </ItemGroup>""");
  83.   <ItemGroup>
  84.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  85.   </ItemGroup>});
复制代码
尝试运行控制台项目,可见此时能够输出以下内容到控制台
  1. 标记了 Foo 特性的类型有: F1,F2
复制代码
尝试展开 Visual Studio 的 依靠项->分析器,如下图所示

可以看到生成的代码如下
  1. using System;
  2. namespace NinahajawhuLairfoheahurcee
  3. {
  4.     public static class GeneratedCode
  5.     {
  6.   <ItemGroup>
  7.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  8.   </ItemGroup>public static void Print()
  9.   <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>{
  12.   <ItemGroup>
  13.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  14.   </ItemGroup>    Console.WriteLine("标记了 Foo 特性的类型有: F2,F1");
  15.   <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>}
  18.     }
  19. }
复制代码
如此以来,对比传统的反射的方法,源代码生成的方式可以将耗时完全放在开发编译过程,不会占用用户端的实行时间。且这个过程都是完完全全的直接代码,也方便运行时的 JIT 举行优化,大大提升了运行时间。完完全全的直接代码也带来了静态分析的友好,可以作为代码裁剪和 AOT 的底层支持
喜欢点点的伙伴也许在准备写 RegisterSourceOutput 的时候,就发现了还有一个名为 RegisterImplementationSourceOutput 方法,那 RegisterSourceOutput 和 RegisterImplementationSourceOutput 的差别是什么?这两个方法对最终生成的代码是没有影响的,焦点差别是 RegisterImplementationSourceOutput 是用来注册具体实现生成的代码,这部分输入的代码会被 IDE 作为可选分析项。如 RegisterImplementationSourceOutput 定名所述,这是一个用来注册“具体实现”的代码,在代码里面,咱可以强行将代码分为“界说代码”和“实现代码”,比如说方法签名是界说代码,方法体是实现代码。从 IDE 的分析角度来看,只对“界说代码”而跳过“实现代码”,可以更大程度的减少分析压力,提升分析速率。通过 RegisterImplementationSourceOutput 方法注册的代码,会被 IDE 作为可选分析项,不会因为生成了大量代码导致 IDE 过于卡顿。但带来的问题是这部分生成代码可能不被加入 IDE 分析,导致业务方调用时飘红。因此通过 RegisterImplementationSourceOutput 生成的代码,基本要求是不会被业务方直接调用。常用的套路是先通过 RegisterSourceOutput 或甚至是 RegisterPostInitializationOutput 生成分部类或分部方法,然后再慢慢在 RegisterImplementationSourceOutput 里面填充实现代码。如果感觉对 RegisterSourceOutput 和 RegisterImplementationSourceOutput 的差别还是很杂乱,没关系,咱将在后文通过实践来让大家更好地理解两者的差别
以上就是通过 ForAttributeWithMetadataName 开始入门编写分析和收集和生成的简单例子,如果对 ForAttributeWithMetadataName 使用方法感爱好,扩展阅读部分请参阅 使用 ForAttributeWithMetadataName 提高 IIncrementalGenerator 增量 Source Generator 源代码生成开发效率和性能
如果大家照着以上的例子编写不出来能构建通过的代码,大概是运行代码不符合预期,欢迎拉取我的示例代码举行阅读
同样的,以上代码放在 githubgitee 上,可以使用如下命令行拉取代码。我整个代码堆栈比力庞大,使用以下命令行可以举行部分拉取,拉取速率比力快
先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
  1. git init
  2. git remote add origin https://gitee.com/lindexi/lindexi_gd.git
  3. git pull origin b8c036de9d9d7c4b1a3d329054086d6566d14dc4
复制代码
以上使用的是国内的 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继承输入以下代码,将 gitee 源换成 github 源举行拉取代码。如果依然拉取不到代码,可以发邮件向我要代码
  1. git remote remove origin
  2. git remote add origin https://github.com/lindexi/lindexi_gd.git
  3. git pull origin b8c036de9d9d7c4b1a3d329054086d6566d14dc4
复制代码
获取代码之后,进入 Roslyn/NinahajawhuLairfoheahurcee 文件夹,即可获取到源代码
更底层的收集分析和生成

阅读到这里,也许大家会感慨,使用 ForAttributeWithMetadataName 还是有很大的限制。比如我的需求任务是分析任意的继承了 IFoo 接口的代码,而没有任何的标志,那应该如何做呢?只通过 ForAttributeWithMetadataName 是无法实现的。这个时候就必要更底层的收集分析和生成技术
本文会和大家介绍 ForAttributeWithMetadataName 仅仅只是因为 ForAttributeWithMetadataName 方法使用简单,且使用频率高。不代表只能通过 ForAttributeWithMetadataName 方法举行分析和生成。实际上,ForAttributeWithMetadataName 方法只是对更底层的收集分析和生成技术的封装,更底层的收集分析和生成技术是可以实现更多的需求任务的
在 IIncrementalGenerator 增量 Source Generator 源代码生成里面提供了众多数据源入口,比如整个的配置、引用的程序集、源代码等等。最焦点也是用最多的就是通过提供的源代码数据源举行收集分析
按照官方的计划,将会分为三个步调完成增量代码生成:

  • 告诉框架层必要关注哪些文件或内容或配置的变更


  • 在有对应的文件等的变更情况下,才会触发后续步调。如此就是增量代码生成的关键

  • 告诉框架层从变更的文件里面感爱好什么数据,对数据预先举行处置惩罚


  • 预先处置惩罚过程中,是会不断举行过滤处置惩罚的,确保只有感爱好的数据才会进入后续步调
  • 其中第一步和第二步可以合在一起

  • 使用给出的数据举行处置惩罚源代码生成逻辑


  • 这一步的逻辑和平常的 Source Generator 是相同的,只是输入的参数不同
按照以上的步调,咱来开始重新实现上文的使用 ForAttributeWithMetadataName 实现的任务需求。这次咱将不使用 ForAttributeWithMetadataName 方法,而是使用更底层的收集分析和生成技术。在这个实现过程中,大家也能感受到使用 ForAttributeWithMetadataName 方法的便捷性
为了方便大家后续拉取代码方便,防止多个版本之间的代码误导。我这里重新新建了两个项目,分别是名为 BegalllalhereCilaywhonerdem.Analyzer 的分析器项目,和一个名为 BegalllalhereCilaywhonerdem 的被分析项目。本文内容里面只给出关键代码片段,如必要全部的项目文件,可在下文找到所有代码的下载方法。如果本身编写的代码构建不通过或运行输出不符合预期,也推荐大家拉取本文的代码举行阅读
先完全按照上文的方式举行项目组织,甚至是完全的代码拷贝。因为接下来咱扼要替换的部分只是将原本的 ForAttributeWithMetadataName 相关代码举行替换而已,其他逻辑依然保持不变
删掉原本的 ForAttributeWithMetadataName 相关代码,即删掉如下代码
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>IncrementalValuesProvider<string> targetClassNameProvider = context.SyntaxProvider.ForAttributeWithMetadataName("Lindexi.FooAttribute",
  4.   <ItemGroup>
  5.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  6.   </ItemGroup>    // 进一步判断
  7.   <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>    (SyntaxNode node, CancellationToken token) => node.IsKind(SyntaxKind.ClassDeclaration),
  10.   <ItemGroup>
  11.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  12.   </ItemGroup>    (GeneratorAttributeSyntaxContext syntaxContext, CancellationToken token) => syntaxContext.TargetSymbol.Name);  <ItemGroup>
  13.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  14.   </ItemGroup>IncrementalValueProvider<ImmutableArray<string>> targetClassNameArrayProvider = targetClassNameProvider
  15.   <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>    .Collect();
复制代码
接下来咱将使用更底层的收集分析和生成技术,即从 context.SyntaxProvider.CreateSyntaxProvider 方法开始
在 context.SyntaxProvider.CreateSyntaxProvider 方法里面包罗两个参数,第一个参数是一个举行语法判断的过程,第二个参数是举行语义进一步判断和加工处置惩罚的逻辑。也就是说 CreateSyntaxProvider 方法就包罗了上文所述的“告诉框架层必要关注哪些文件或内容或配置的变更”和“告诉框架层从变更的文件里面感爱好什么数据,对数据预先举行处置惩罚”两个步调
在 CreateSyntaxProvider 方法里面,第一步的语法判断是判断当前传入的是否类型界说。如果是类型界说,则读取其标志的特性,判断特性满足 Lindexi.FooAttribute 的特性时,则算语法判断通过,让数据走到下面的语义判断处置惩罚上。其代码大概如下
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>IncrementalValueProvider<ImmutableArray<string>> targetClassNameArrayProvider = context.SyntaxProvider
  4.   <ItemGroup>
  5.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  6.   </ItemGroup>    .CreateSyntaxProvider((node, _) =>
  7.   <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>    {
  10.   <ItemGroup>
  11.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  12.   </ItemGroup>  <ItemGroup>
  13.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  14.   </ItemGroup>if (node is not ClassDeclarationSyntax classDeclarationSyntax)
  15.   <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>{
  20.   <ItemGroup>
  21.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  22.   </ItemGroup>  <ItemGroup>
  23.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  24.   </ItemGroup>    return false;
  25.   <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>}
  30.   <ItemGroup>
  31.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  32.   </ItemGroup>  <ItemGroup>
  33.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  34.   </ItemGroup>// 为什么这里是 Attribute List 的集合?原因是可以写出这样的语法
  35.   <ItemGroup>
  36.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  37.   </ItemGroup>  <ItemGroup>
  38.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  39.   </ItemGroup>// ```csharp
  40.   <ItemGroup>
  41.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  42.   </ItemGroup>  <ItemGroup>
  43.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  44.   </ItemGroup>// [A1Attribute, A2Attribute]
  45.   <ItemGroup>
  46.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  47.   </ItemGroup>  <ItemGroup>
  48.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  49.   </ItemGroup>// [A3Attribute]
  50.   <ItemGroup>
  51.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  52.   </ItemGroup>  <ItemGroup>
  53.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  54.   </ItemGroup>// private void Foo()
  55.   <ItemGroup>
  56.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  57.   </ItemGroup>  <ItemGroup>
  58.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  59.   </ItemGroup>// {
  60.   <ItemGroup>
  61.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  62.   </ItemGroup>  <ItemGroup>
  63.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  64.   </ItemGroup>// }
  65.   <ItemGroup>
  66.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  67.   </ItemGroup>  <ItemGroup>
  68.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  69.   </ItemGroup>// ```
  70.   <ItemGroup>
  71.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  72.   </ItemGroup>  <ItemGroup>
  73.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  74.   </ItemGroup>foreach (AttributeListSyntax attributeListSyntax in classDeclarationSyntax.AttributeLists)
  75.   <ItemGroup>
  76.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  77.   </ItemGroup>  <ItemGroup>
  78.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  79.   </ItemGroup>{
  80.   <ItemGroup>
  81.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  82.   </ItemGroup>  <ItemGroup>
  83.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  84.   </ItemGroup>    foreach (AttributeSyntax attributeSyntax in attributeListSyntax.Attributes)
  85.   <ItemGroup>
  86.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  87.   </ItemGroup>  <ItemGroup>
  88.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  89.   </ItemGroup>    {
  90.   <ItemGroup>
  91.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  92.   </ItemGroup>  <ItemGroup>
  93.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  94.   </ItemGroup>  <ItemGroup>
  95.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  96.   </ItemGroup>NameSyntax name = attributeSyntax.Name;
  97.   <ItemGroup>
  98.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  99.   </ItemGroup>  <ItemGroup>
  100.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  101.   </ItemGroup>  <ItemGroup>
  102.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  103.   </ItemGroup>string nameText = name.ToFullString();
  104.   <ItemGroup>
  105.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  106.   </ItemGroup>  <ItemGroup>
  107.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  108.   </ItemGroup>  <ItemGroup>
  109.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  110.   </ItemGroup>if (nameText == "Foo")
  111.   <ItemGroup>
  112.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  113.   </ItemGroup>  <ItemGroup>
  114.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  115.   </ItemGroup>  <ItemGroup>
  116.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  117.   </ItemGroup>{
  118.   <ItemGroup>
  119.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  120.   </ItemGroup>  <ItemGroup>
  121.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  122.   </ItemGroup>  <ItemGroup>
  123.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  124.   </ItemGroup>    return true;
  125.   <ItemGroup>
  126.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  127.   </ItemGroup>  <ItemGroup>
  128.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  129.   </ItemGroup>  <ItemGroup>
  130.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  131.   </ItemGroup>}
  132.   <ItemGroup>
  133.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  134.   </ItemGroup>  <ItemGroup>
  135.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  136.   </ItemGroup>  <ItemGroup>
  137.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  138.   </ItemGroup>if (nameText == "FooAttribute")
  139.   <ItemGroup>
  140.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  141.   </ItemGroup>  <ItemGroup>
  142.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  143.   </ItemGroup>  <ItemGroup>
  144.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  145.   </ItemGroup>{
  146.   <ItemGroup>
  147.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  148.   </ItemGroup>  <ItemGroup>
  149.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  150.   </ItemGroup>  <ItemGroup>
  151.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  152.   </ItemGroup>    return true;
  153.   <ItemGroup>
  154.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  155.   </ItemGroup>  <ItemGroup>
  156.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  157.   </ItemGroup>  <ItemGroup>
  158.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  159.   </ItemGroup>}
  160.   <ItemGroup>
  161.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  162.   </ItemGroup>  <ItemGroup>
  163.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  164.   </ItemGroup>  <ItemGroup>
  165.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  166.   </ItemGroup>// 可能还有 global::Lindexi.FooAttribute 的情况
  167.   <ItemGroup>
  168.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  169.   </ItemGroup>  <ItemGroup>
  170.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  171.   </ItemGroup>  <ItemGroup>
  172.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  173.   </ItemGroup>if (nameText.EndsWith("Lindexi.FooAttribute"))
  174.   <ItemGroup>
  175.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  176.   </ItemGroup>  <ItemGroup>
  177.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  178.   </ItemGroup>  <ItemGroup>
  179.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  180.   </ItemGroup>{
  181.   <ItemGroup>
  182.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  183.   </ItemGroup>  <ItemGroup>
  184.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  185.   </ItemGroup>  <ItemGroup>
  186.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  187.   </ItemGroup>    return true;
  188.   <ItemGroup>
  189.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  190.   </ItemGroup>  <ItemGroup>
  191.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  192.   </ItemGroup>  <ItemGroup>
  193.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  194.   </ItemGroup>}
  195.   <ItemGroup>
  196.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  197.   </ItemGroup>  <ItemGroup>
  198.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  199.   </ItemGroup>  <ItemGroup>
  200.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  201.   </ItemGroup>if (nameText.EndsWith("Lindexi.Foo"))
  202.   <ItemGroup>
  203.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  204.   </ItemGroup>  <ItemGroup>
  205.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  206.   </ItemGroup>  <ItemGroup>
  207.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  208.   </ItemGroup>{
  209.   <ItemGroup>
  210.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  211.   </ItemGroup>  <ItemGroup>
  212.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  213.   </ItemGroup>  <ItemGroup>
  214.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  215.   </ItemGroup>    return true;
  216.   <ItemGroup>
  217.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  218.   </ItemGroup>  <ItemGroup>
  219.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  220.   </ItemGroup>  <ItemGroup>
  221.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  222.   </ItemGroup>}
  223.   <ItemGroup>
  224.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  225.   </ItemGroup>  <ItemGroup>
  226.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  227.   </ItemGroup>    }
  228.   <ItemGroup>
  229.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  230.   </ItemGroup>  <ItemGroup>
  231.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  232.   </ItemGroup>}
  233.   <ItemGroup>
  234.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  235.   </ItemGroup>  <ItemGroup>
  236.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  237.   </ItemGroup>return false;
  238.   <ItemGroup>
  239.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  240.   </ItemGroup>    }, (syntaxContext, _) =>
  241.   <ItemGroup>
  242.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  243.   </ItemGroup>    {
  244.   <ItemGroup>
  245.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  246.   </ItemGroup>  <ItemGroup>
  247.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  248.   </ItemGroup>// 先忽略语义处理过程代码
  249.   <ItemGroup>
  250.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  251.   </ItemGroup>    }).Collect();
复制代码
如上述的代码所示,起首是颠末 if (node is not ClassDeclarationSyntax classDeclarationSyntax) 判断,过滤掉非类型界说部分的代码。此时就可以确保大量的代码都不会进入到后续分支。毕竟对于正常的代码逻辑来说,类型的界说还是少数哈。接着的逻辑编写就有些考大家对于 C# 的基础语法知识了,先获取特性列表。这里获取到的是列表的集合,为什么呢?因为在 C# 代码里面答应以下的写法,如上文代码解释所述
  1. [A1Attribute, A2Attribute]
  2. [A3Attribute]
  3. private void Foo()
  4. {
  5. }
复制代码
以上代码里面的 [A1Attribute, A2Attribute] 就是一个特性列表,而 [A1Attribute, A2Attribute] 和  A3Attribute 三个特性构成了特性列表的集合,如此才能保证能够获取到所有的特性且不丢失语法上的特性。即可能某些特性是和其他的特性写在一起的特性才不会被丢失。这就是为什么必要有两层的 foreach 循环才能遍历所有的特性的缘故原由
在语法层面上,是不能完全判断一个特性是否真的是某个指定类型的特性的,比如说对以下代码的分析
  1. [Foo]
  2. public class F1
  3. {
  4. }
复制代码
在语法层面上只能知道 F1 类型标志了 [Foo] 特性,但不知道这个 [Foo] 特性是否真的是 Lindexi.FooAttribute 特性。必要在语义分析过程中,进一步判断是否真的是 Lindexi.FooAttribute 特性。语法层面上只能知道写下去的是什么代码,完全字面量。这也就是为什么上面代码的判断逻辑会额外多了那么多判断的缘故原由。固然了,如果大家图省事,那直接判断是否包罗 Foo 字符串也可以的
上面代码使用了对 NameSyntax 调用 ToFullString 方法获取到所标志的名,再通过字符串判断逻辑,判断是否可能是标志了 Lindexi.FooAttribute 特性
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>NameSyntax name = attributeSyntax.Name;
  8.   <ItemGroup>
  9.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  10.   </ItemGroup>  <ItemGroup>
  11.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  12.   </ItemGroup>  <ItemGroup>
  13.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  14.   </ItemGroup>string nameText = name.ToFullString();
  15.   <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>if (nameText == "Foo")
  22.   <ItemGroup>
  23.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  24.   </ItemGroup>  <ItemGroup>
  25.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  26.   </ItemGroup>  <ItemGroup>
  27.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  28.   </ItemGroup>{
  29.   <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>  <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>  <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>    return true;
  36.   <ItemGroup>
  37.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  38.   </ItemGroup>  <ItemGroup>
  39.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  40.   </ItemGroup>  <ItemGroup>
  41.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  42.   </ItemGroup>}
  43.   <ItemGroup>
  44.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  45.   </ItemGroup>  <ItemGroup>
  46.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  47.   </ItemGroup>  <ItemGroup>
  48.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  49.   </ItemGroup>if (nameText == "FooAttribute")
  50.   <ItemGroup>
  51.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  52.   </ItemGroup>  <ItemGroup>
  53.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  54.   </ItemGroup>  <ItemGroup>
  55.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  56.   </ItemGroup>{
  57.   <ItemGroup>
  58.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  59.   </ItemGroup>  <ItemGroup>
  60.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  61.   </ItemGroup>  <ItemGroup>
  62.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  63.   </ItemGroup>    return true;
  64.   <ItemGroup>
  65.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  66.   </ItemGroup>  <ItemGroup>
  67.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  68.   </ItemGroup>  <ItemGroup>
  69.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  70.   </ItemGroup>}
  71.   <ItemGroup>
  72.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  73.   </ItemGroup>  <ItemGroup>
  74.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  75.   </ItemGroup>  <ItemGroup>
  76.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  77.   </ItemGroup>// 可能还有 global::Lindexi.FooAttribute 的情况
  78.   <ItemGroup>
  79.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  80.   </ItemGroup>  <ItemGroup>
  81.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  82.   </ItemGroup>  <ItemGroup>
  83.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  84.   </ItemGroup>if (nameText.EndsWith("Lindexi.FooAttribute"))
  85.   <ItemGroup>
  86.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  87.   </ItemGroup>  <ItemGroup>
  88.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  89.   </ItemGroup>  <ItemGroup>
  90.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  91.   </ItemGroup>{
  92.   <ItemGroup>
  93.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  94.   </ItemGroup>  <ItemGroup>
  95.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  96.   </ItemGroup>  <ItemGroup>
  97.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  98.   </ItemGroup>    return true;
  99.   <ItemGroup>
  100.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  101.   </ItemGroup>  <ItemGroup>
  102.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  103.   </ItemGroup>  <ItemGroup>
  104.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  105.   </ItemGroup>}
  106.   <ItemGroup>
  107.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  108.   </ItemGroup>  <ItemGroup>
  109.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  110.   </ItemGroup>  <ItemGroup>
  111.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  112.   </ItemGroup>if (nameText.EndsWith("Lindexi.Foo"))
  113.   <ItemGroup>
  114.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  115.   </ItemGroup>  <ItemGroup>
  116.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  117.   </ItemGroup>  <ItemGroup>
  118.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  119.   </ItemGroup>{
  120.   <ItemGroup>
  121.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  122.   </ItemGroup>  <ItemGroup>
  123.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  124.   </ItemGroup>  <ItemGroup>
  125.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  126.   </ItemGroup>    return true;
  127.   <ItemGroup>
  128.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  129.   </ItemGroup>  <ItemGroup>
  130.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  131.   </ItemGroup>  <ItemGroup>
  132.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  133.   </ItemGroup>}
复制代码
如果大家对以上的  NameSyntax 的 ToFullString 感爱好,请参阅 Roslyn NameSyntax 的 ToString 和 ToFullString 的区别
虽然上文判断逻辑看起来写的很多,但也不代表能通过语法判断逻辑的,就一定是标志了 Lindexi.FooAttribute 特性。在语义部分举行进一步处置惩罚,代码如下
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>  context.SyntaxProvider
  4.   <ItemGroup>
  5.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  6.   </ItemGroup>    .CreateSyntaxProvider((node, _) =>
  7.   <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>    {
  10.   <ItemGroup>
  11.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  12.   </ItemGroup>  <ItemGroup>
  13.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  14.   </ItemGroup>// 忽略语法处理部分代码
  15.   <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>    }, (syntaxContext, _) =>
  18.   <ItemGroup>
  19.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  20.   </ItemGroup>    {
  21.   <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>ISymbol declaredSymbol = syntaxContext.SemanticModel.GetDeclaredSymbol(syntaxContext.Node);
  26.   <ItemGroup>
  27.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  28.   </ItemGroup>  <ItemGroup>
  29.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  30.   </ItemGroup>if (declaredSymbol is not INamedTypeSymbol namedTypeSymbol)
  31.   <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>  <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>{
  36.   <ItemGroup>
  37.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  38.   </ItemGroup>  <ItemGroup>
  39.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  40.   </ItemGroup>    return (string) null;
  41.   <ItemGroup>
  42.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  43.   </ItemGroup>  <ItemGroup>
  44.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  45.   </ItemGroup>}
  46.   <ItemGroup>
  47.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  48.   </ItemGroup>  <ItemGroup>
  49.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  50.   </ItemGroup>ImmutableArray<AttributeData> attributeDataArray = namedTypeSymbol.GetAttributes();
  51.   <ItemGroup>
  52.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  53.   </ItemGroup>  <ItemGroup>
  54.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  55.   </ItemGroup>// 在通过语义判断一次,防止被骗了
  56.   <ItemGroup>
  57.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  58.   </ItemGroup>  <ItemGroup>
  59.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  60.   </ItemGroup>if (!attributeDataArray.Any(t =>
  61.   <ItemGroup>
  62.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  63.   </ItemGroup>  <ItemGroup>
  64.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  65.   </ItemGroup>  <ItemGroup>
  66.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  67.   </ItemGroup>t.AttributeClass?.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) ==
  68.   <ItemGroup>
  69.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  70.   </ItemGroup>  <ItemGroup>
  71.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  72.   </ItemGroup>  <ItemGroup>
  73.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  74.   </ItemGroup>"global::Lindexi.FooAttribute"))
  75.   <ItemGroup>
  76.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  77.   </ItemGroup>  <ItemGroup>
  78.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  79.   </ItemGroup>{
  80.   <ItemGroup>
  81.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  82.   </ItemGroup>  <ItemGroup>
  83.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  84.   </ItemGroup>    return (string) null;
  85.   <ItemGroup>
  86.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  87.   </ItemGroup>  <ItemGroup>
  88.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  89.   </ItemGroup>}
  90.   <ItemGroup>
  91.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  92.   </ItemGroup>  <ItemGroup>
  93.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  94.   </ItemGroup>return namedTypeSymbol.Name;
  95.   <ItemGroup>
  96.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  97.   </ItemGroup>    })
复制代码
由于在语法分析过程中,只能知道标志了名为 Foo 的特性,不知道是否真的是特性。必要在语义分析过程中,进一步判断是否真的是特性。进一步判断的方法就是通过 GetAttributes 方法获取标志在类型上面的特性,此时和语法不同的是,可以拿到分部类上面标志的特性,不单单只是某个类型文件而已。接着使用 ToDisplayString 方法获取标志的特性的全名,判断全名是否为 global:indexi.FooAttribute 从而确保类型符合预期。固然了,这个过程里面,咱是省略了判断 global:indexi.FooAttribute 特性是属于哪个程序集的。正常的分析器项目里面也不会真的去判断某个全名的类型属于哪个程序集的。这个方法便是缺陷也是功能,方便很多开发者只要写出来“鸭子”类型即可的行为。这里说的“鸭子”行为就是只要一个类型的定名空间和名字符合约定即可,至于这个类型是放在哪个程序集和用什么方式的可访问描述都不重要。许多的 C# 高版本语法也是这么界说出来的,如 init 或 ValueTuple 等等。因为通过这样的计划,可以更好的让 C# 语言和具体的框架分离,这也是 C# dotnet 的计划基本原则
在通过了语义判断逻辑之后,即可决定返回值是 (string) null 还是 namedTypeSymbol.Name 的值。返回值这一步就对应着 “告诉框架层从变更的文件里面感爱好什么数据,对数据预先举行处置惩罚”步调
合起来的代码实现如下
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>IncrementalValueProvider targetClassNameArrayProvider = context.SyntaxProvider  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>    .CreateSyntaxProvider((node, _) =>  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>    {  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>if (node is not ClassDeclarationSyntax classDeclarationSyntax)  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>{  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>    return false;  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>}  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>// 为什么这里是 Attribute List 的集合?缘故原由是可以写出这样的语法  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>  <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>// ```csharp  <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>  <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>// [A1Attribute, A2Attribute]  <ItemGroup>
  36.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  37.   </ItemGroup>  <ItemGroup>
  38.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  39.   </ItemGroup>// [A3Attribute]  <ItemGroup>
  40.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  41.   </ItemGroup>  <ItemGroup>
  42.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  43.   </ItemGroup>// private void Foo()  <ItemGroup>
  44.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  45.   </ItemGroup>  <ItemGroup>
  46.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  47.   </ItemGroup>// {  <ItemGroup>
  48.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  49.   </ItemGroup>  <ItemGroup>
  50.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  51.   </ItemGroup>// }  <ItemGroup>
  52.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  53.   </ItemGroup>  <ItemGroup>
  54.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  55.   </ItemGroup>// ```  <ItemGroup>
  56.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  57.   </ItemGroup>  <ItemGroup>
  58.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  59.   </ItemGroup>foreach (AttributeListSyntax attributeListSyntax in classDeclarationSyntax.AttributeLists)  <ItemGroup>
  60.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  61.   </ItemGroup>  <ItemGroup>
  62.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  63.   </ItemGroup>{  <ItemGroup>
  64.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  65.   </ItemGroup>  <ItemGroup>
  66.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  67.   </ItemGroup>    foreach (AttributeSyntax attributeSyntax in attributeListSyntax.Attributes)  <ItemGroup>
  68.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  69.   </ItemGroup>  <ItemGroup>
  70.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  71.   </ItemGroup>    {  <ItemGroup>
  72.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  73.   </ItemGroup>  <ItemGroup>
  74.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  75.   </ItemGroup>  <ItemGroup>
  76.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  77.   </ItemGroup>NameSyntax name = attributeSyntax.Name;
  78.   <ItemGroup>
  79.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  80.   </ItemGroup>  <ItemGroup>
  81.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  82.   </ItemGroup>  <ItemGroup>
  83.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  84.   </ItemGroup>string nameText = name.ToFullString();
  85.   <ItemGroup>
  86.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  87.   </ItemGroup>  <ItemGroup>
  88.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  89.   </ItemGroup>  <ItemGroup>
  90.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  91.   </ItemGroup>if (nameText == "Foo")
  92.   <ItemGroup>
  93.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  94.   </ItemGroup>  <ItemGroup>
  95.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  96.   </ItemGroup>  <ItemGroup>
  97.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  98.   </ItemGroup>{
  99.   <ItemGroup>
  100.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  101.   </ItemGroup>  <ItemGroup>
  102.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  103.   </ItemGroup>  <ItemGroup>
  104.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  105.   </ItemGroup>    return true;
  106.   <ItemGroup>
  107.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  108.   </ItemGroup>  <ItemGroup>
  109.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  110.   </ItemGroup>  <ItemGroup>
  111.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  112.   </ItemGroup>}
  113.   <ItemGroup>
  114.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  115.   </ItemGroup>  <ItemGroup>
  116.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  117.   </ItemGroup>  <ItemGroup>
  118.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  119.   </ItemGroup>if (nameText == "FooAttribute")
  120.   <ItemGroup>
  121.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  122.   </ItemGroup>  <ItemGroup>
  123.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  124.   </ItemGroup>  <ItemGroup>
  125.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  126.   </ItemGroup>{
  127.   <ItemGroup>
  128.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  129.   </ItemGroup>  <ItemGroup>
  130.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  131.   </ItemGroup>  <ItemGroup>
  132.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  133.   </ItemGroup>    return true;
  134.   <ItemGroup>
  135.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  136.   </ItemGroup>  <ItemGroup>
  137.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  138.   </ItemGroup>  <ItemGroup>
  139.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  140.   </ItemGroup>}
  141.   <ItemGroup>
  142.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  143.   </ItemGroup>  <ItemGroup>
  144.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  145.   </ItemGroup>  <ItemGroup>
  146.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  147.   </ItemGroup>// 可能还有 global::Lindexi.FooAttribute 的情况
  148.   <ItemGroup>
  149.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  150.   </ItemGroup>  <ItemGroup>
  151.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  152.   </ItemGroup>  <ItemGroup>
  153.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  154.   </ItemGroup>if (nameText.EndsWith("Lindexi.FooAttribute"))
  155.   <ItemGroup>
  156.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  157.   </ItemGroup>  <ItemGroup>
  158.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  159.   </ItemGroup>  <ItemGroup>
  160.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  161.   </ItemGroup>{
  162.   <ItemGroup>
  163.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  164.   </ItemGroup>  <ItemGroup>
  165.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  166.   </ItemGroup>  <ItemGroup>
  167.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  168.   </ItemGroup>    return true;
  169.   <ItemGroup>
  170.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  171.   </ItemGroup>  <ItemGroup>
  172.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  173.   </ItemGroup>  <ItemGroup>
  174.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  175.   </ItemGroup>}
  176.   <ItemGroup>
  177.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  178.   </ItemGroup>  <ItemGroup>
  179.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  180.   </ItemGroup>  <ItemGroup>
  181.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  182.   </ItemGroup>if (nameText.EndsWith("Lindexi.Foo"))
  183.   <ItemGroup>
  184.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  185.   </ItemGroup>  <ItemGroup>
  186.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  187.   </ItemGroup>  <ItemGroup>
  188.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  189.   </ItemGroup>{
  190.   <ItemGroup>
  191.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  192.   </ItemGroup>  <ItemGroup>
  193.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  194.   </ItemGroup>  <ItemGroup>
  195.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  196.   </ItemGroup>    return true;
  197.   <ItemGroup>
  198.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  199.   </ItemGroup>  <ItemGroup>
  200.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  201.   </ItemGroup>  <ItemGroup>
  202.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  203.   </ItemGroup>}  <ItemGroup>
  204.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  205.   </ItemGroup>  <ItemGroup>
  206.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  207.   </ItemGroup>    }  <ItemGroup>
  208.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  209.   </ItemGroup>  <ItemGroup>
  210.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  211.   </ItemGroup>}  <ItemGroup>
  212.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  213.   </ItemGroup>  <ItemGroup>
  214.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  215.   </ItemGroup>return false;  <ItemGroup>
  216.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  217.   </ItemGroup>    }, (syntaxContext, _) =>  <ItemGroup>
  218.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  219.   </ItemGroup>    {  <ItemGroup>
  220.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  221.   </ItemGroup>  <ItemGroup>
  222.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  223.   </ItemGroup>ISymbol declaredSymbol = syntaxContext.SemanticModel.GetDeclaredSymbol(syntaxContext.Node);  <ItemGroup>
  224.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  225.   </ItemGroup>  <ItemGroup>
  226.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  227.   </ItemGroup>if (declaredSymbol is not INamedTypeSymbol namedTypeSymbol)  <ItemGroup>
  228.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  229.   </ItemGroup>  <ItemGroup>
  230.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  231.   </ItemGroup>{  <ItemGroup>
  232.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  233.   </ItemGroup>  <ItemGroup>
  234.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  235.   </ItemGroup>    return (string) null;  <ItemGroup>
  236.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  237.   </ItemGroup>  <ItemGroup>
  238.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  239.   </ItemGroup>}  <ItemGroup>
  240.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  241.   </ItemGroup>  <ItemGroup>
  242.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  243.   </ItemGroup>ImmutableArray attributeDataArray = namedTypeSymbol.GetAttributes();  <ItemGroup>
  244.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  245.   </ItemGroup>  <ItemGroup>
  246.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  247.   </ItemGroup>// 在通过语义判断一次,防止被骗了  <ItemGroup>
  248.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  249.   </ItemGroup>  <ItemGroup>
  250.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  251.   </ItemGroup>if (!attributeDataArray.Any(t =>  <ItemGroup>
  252.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  253.   </ItemGroup>  <ItemGroup>
  254.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  255.   </ItemGroup>  <ItemGroup>
  256.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  257.   </ItemGroup>t.AttributeClass?.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) ==  <ItemGroup>
  258.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  259.   </ItemGroup>  <ItemGroup>
  260.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  261.   </ItemGroup>  <ItemGroup>
  262.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  263.   </ItemGroup>"global::Lindexi.FooAttribute"))  <ItemGroup>
  264.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  265.   </ItemGroup>  <ItemGroup>
  266.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  267.   </ItemGroup>{  <ItemGroup>
  268.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  269.   </ItemGroup>  <ItemGroup>
  270.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  271.   </ItemGroup>    return (string) null;  <ItemGroup>
  272.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  273.   </ItemGroup>  <ItemGroup>
  274.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  275.   </ItemGroup>}  <ItemGroup>
  276.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  277.   </ItemGroup>  <ItemGroup>
  278.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  279.   </ItemGroup>return namedTypeSymbol.Name;  <ItemGroup>
  280.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  281.   </ItemGroup>    }).Collect();
复制代码
依然和 使用 ForAttributeWithMetadataName 快速分析代码 章一样,将 targetClassNameArrayProvider 注册到输出源代码中,如下所示
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>context.RegisterSourceOutput(targetClassNameArrayProvider, (productionContext, classNameArray) =>
  4.   <ItemGroup>
  5.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  6.   </ItemGroup>{
  7.   <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>     ... // 一摸一样的生成代码
  10.   <ItemGroup>
  11.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  12.   </ItemGroup>});
复制代码
这就是直接使用 CreateSyntaxProvider 方法举行语法语义分析代替 ForAttributeWithMetadataName 的方式
以上代码放在 githubgitee 上,可以使用如下命令行拉取代码。我整个代码堆栈比力庞大,使用以下命令行可以举行部分拉取,拉取速率比力快
先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
  1. git init
  2. git remote add origin https://gitee.com/lindexi/lindexi_gd.git
  3. git pull origin cde8c2a0bd1da7a17467655ff1fc1d78ad28fbed
复制代码
以上使用的是国内的 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继承输入以下代码,将 gitee 源换成 github 源举行拉取代码。如果依然拉取不到代码,可以发邮件向我要代码
  1. git remote remove origin
  2. git remote add origin https://github.com/lindexi/lindexi_gd.git
  3. git pull origin cde8c2a0bd1da7a17467655ff1fc1d78ad28fbed
复制代码
获取代码之后,进入 Roslyn/BegalllalhereCilaywhonerdem 文件夹,即可获取到源代码
改用更底层的收集分析和生成之后,可以看到语法分析的过程的逻辑已经是比力复杂了。这个过程无论是为了提升可调试性也好,还是提升健壮性也好,其中一个重要本事就是为其编写单元测试。当可能存在的条件情况比力多的时候,编写单元测试可以让大家更好的快速模拟各种情况,也能固化行为,防止后续变更逻辑的时候破坏原有的逻辑。接下来我将和大家介绍如何为分析器编写单元测试
编写单元测试

为了方便大家获取到精确的代码,我这里依然还是再次新建两个新的项目,分别是名为 ChunecilarkenaLibeewhemke 的分析器项目,和名为 ChunecilarkenaLibeewhemke.Test 的单元测试项目。其中名为 ChunecilarkenaLibeewhemke 的分析器项目里面的内容和上一章提供的代码相同,在本章里面咱重点将放在单元测试项目上
先设置让 ChunecilarkenaLibeewhemke.Test 单元测试项目引用 ChunecilarkenaLibeewhemke 分析器项目。和前文提及的引用分析器项目不同的是,在单元测试里面就应该添加程序集应用,如此才能够让单元测试项目访问到分析器项目标公开成员,从而举行测试。以下是我设置了单元测试引用分析器项目之后的 ChunecilarkenaLibeewhemke.Test 单元测试项目标 csproj 项目文件代码片段
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>
复制代码
以上代码里面的 OutputItemType="Analyzer" 是可选的,仅仅用在盼望额外将单元测试项目也当成被分析项目时才添加。默认 ReferenceOutputAssembly 属性值就是 true 值,这里强行写 ReferenceOutputAssembly="true" 只是为了强调而已,默认不写即可。即默认情况下,只需使用  代码引用即可,和其他单元测试项目没有什么差别
单元测试项目必要添加单元测试负载,这里必要额外添加针对分析器的负载。添加之后的 ChunecilarkenaLibeewhemke.Test 单元测试项目标 csproj 项目文件的代码如下
  1.       net8.0    enable    enable  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>  
复制代码
单元测试项目可以是尽可能的高版本的 .NET 版本,只有分析器项目才在当前为了兼容 VisualStudio 才必要选用旧的 netstandard2.0 版本。单元测试项目是可以独立实行的,也不会被其他模块引用,尽可能高版本可以享用更新的技术
完成单元测试项目标基础准备之后,接下来咱开始新建名为 IncrementalGeneratorTest 的单元测试类。在对分析器,特殊是源代码生成器的单元测试中,一般都会通过一个本身编写的 CreateCompilation 方法,这个方法的作用是将传入的源代码字符串封装为 CSharpCompilation 类型。接着使用 CSharpGeneratorDriver 实行指定的源代码生成器
常用的封装 CSharpCompilation 代码的 CreateCompilation 方法代码如下。可以简单将 CSharpCompilation 理解为一个虚拟的项目。一个虚拟的项目重要的部分只有两个,一个就是源代码本身,另一个就是所引用的程序集。在单元测试的源代码本身就是通过 CSharpSyntaxTree.ParseText 方法将源代码转换为 SyntaxTree 对象。引用程序集可能会复杂一些,在咱这个单元测试里面只必要带上 System.Runtime 程序集即可,带上的方法是通过某个 System.Runtime 程序集的类型,如 System.Reflection.Binder 类型,取其类型所在程序集的路径,再通过 MetadataReference.CreateFromFile 作为引用路径
  1.     private static CSharpCompilation CreateCompilation(string source)  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>=> CSharpCompilation.Create("compilation",  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>    new[] { CSharpSyntaxTree.ParseText(source, path: "Foo.cs") },  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>    new[]  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>    {  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>// 如果缺少引用,那将会导致单元测试有些符号无法寻找精确,从而导致剖析失败  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>MetadataReference.CreateFromFile(typeof(Binder).GetTypeInfo().Assembly.Location)  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>    },  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>    new CSharpCompilationOptions(OutputKind.ConsoleApplication));
复制代码
大部分情况下的分析器单元测试项目标 CSharpCompilation 封装代码相对固定,会变更的只有某些引用逻辑而已
开始编写单元测试方法,如以下代码所示
  1. [TestClass]public class IncrementalGeneratorTest{    [TestMethod]    public void Test()    {  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>... // 在这里编写单元测试代码    }}
复制代码
先添加用于测试输入的代码,即假装是项目标代码,我将其放在 testCode 变量里面,代码如下
  1.     [TestMethod]    public void Test()    {  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>var testCode =  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>    """  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>    using System;  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>    using Lindexi;  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>    namespace ChunecilarkenaLibeewhemke.Test  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>    {  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>[Foo]  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>public class F1  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>{  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>}  <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>  <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>  <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>    [FooAttribute]  <ItemGroup>
  36.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  37.   </ItemGroup>  <ItemGroup>
  38.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  39.   </ItemGroup>public class F2  <ItemGroup>
  40.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  41.   </ItemGroup>  <ItemGroup>
  42.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  43.   </ItemGroup>{  <ItemGroup>
  44.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  45.   </ItemGroup>  <ItemGroup>
  46.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  47.   </ItemGroup>}  <ItemGroup>
  48.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  49.   </ItemGroup>    }  <ItemGroup>
  50.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  51.   </ItemGroup>    """;  <ItemGroup>
  52.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  53.   </ItemGroup>... // 继承添加更多代码    }
复制代码
先调用刚才的 CreateCompilation 方法,将 testCode 封装为 CSharpCompilation 对象。再创建出盼望测试的源代码生成器类型。在一个分析器里面里面可以包罗非常多个源代码生成器,在单元测试里面可以非常方便取出盼望举行测试的源代码生成器,举行非常特定的测试。这也是单元测试能够带来的多入口的优势。本文这里将测试本身项目里面的名为 IncrementalGenerator 的源代码生成器
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>var generator = new IncrementalGenerator();
复制代码
调用 CSharpGeneratorDriver.Create 创建出 GeneratorDriver 对象,用于在单元测试里面实行源代码生成器,从而获取实在行结果。这里必要说明的是整个 Roslyn 都在贯穿不可变计划。不例外,这个 GeneratorDriver 类型也是不可变对象,即在实行源代码生成器之后,是返回一个新的 GeneratorDriver 对象,原本的对象的状态是不改变的。这个计划上可能会让一些伙伴踩坑,让伙伴们发现在实行源代码生成器之后,调用 GeneratorDriver 的 GetRunResult 方法拿不到结果,这是因为调用的 GeneratorDriver 对象还是旧的对象,而是不实行源代码生成器之后的新的对象
为什么 Roslyn 要这么计划 GeneratorDriver 类型呢?除了不可变能够带来很大程度上的降低程序复杂度,方便出现问题快速重现问题和获取过程状态之外。另一个重要缘故原由是可以让 IDE 从某个状态重复多次快速进入下一个状态,而不必要每次都创建新的对象。如咱在某个方法里面开始编写代码,从进入方法开始的状态就可以保留,不断编写代码,不断输入字符或单词的过程中,就可以不断背景调用 GeneratorDriver 对象举行实行源代码生成状态,而不必要每输入一次都创建一次新的对象。如此可以更好的提升 IDE 的性能
合起来的代码如下
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>var generator = new IncrementalGenerator();  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
复制代码
调用 CSharpGeneratorDriver 的 RunGenerators 实行源代码生成器,记得获取其方法返回值作为新的对象,代码如下
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>var generator = new IncrementalGenerator();  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>GeneratorDriver driver2 = driver.RunGenerators(compilation);
复制代码
尝试获取 driver2 的结果,获取到源代码生成器输出的源代码内容,代码如下
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>foreach (var generatedTree in driver2.GetRunResult().GeneratedTrees)  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>{  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>    var generatedCode = generatedTree.ToString();  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>    Debug.WriteLine(generatedCode);  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>}
复制代码
这就是最简单的源代码生成器的单元测试的写法。如果大家对分析器的单元测试感爱好,可以继承阅读此博客:为 IIncrementalGenerator 增量 Source Generator 源代码生成项目添加单元测试
在完成单元测试的搭建之后,自然咱可以添加更多测试逻辑。比如说上文提及的在语法层面上只能知道一个类型标志了名为 Foo 的特性,而不知此 Foo 具体的是什么样的类型。必要通过进一步的语义过程的判断处置惩罚。在这里,咱将通过单元测试构建出这样的情况,举行测试咱的源代码生成器逻辑
编辑放在 testCode 的代码,给其添加一些捣乱的代码,更改之后的代码如下
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>var testCode =  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>    """  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>    using System;  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>    using Lindexi;  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>    namespace ChunecilarkenaLibeewhemke.Test  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>    {  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>[Foo]  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>public class F1  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>{  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>}  <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>  <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>  <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>    [FooAttribute]  <ItemGroup>
  36.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  37.   </ItemGroup>  <ItemGroup>
  38.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  39.   </ItemGroup>public class F2  <ItemGroup>
  40.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  41.   </ItemGroup>  <ItemGroup>
  42.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  43.   </ItemGroup>{  <ItemGroup>
  44.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  45.   </ItemGroup>  <ItemGroup>
  46.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  47.   </ItemGroup>}  <ItemGroup>
  48.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  49.   </ItemGroup>    }  <ItemGroup>
  50.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  51.   </ItemGroup>    namespace FooChunecilarkenaLibeewhemke  <ItemGroup>
  52.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  53.   </ItemGroup>    {  <ItemGroup>
  54.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  55.   </ItemGroup>  <ItemGroup>
  56.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  57.   </ItemGroup>public class FooAttribute : Attribute  <ItemGroup>
  58.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  59.   </ItemGroup>  <ItemGroup>
  60.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  61.   </ItemGroup>{  <ItemGroup>
  62.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  63.   </ItemGroup>  <ItemGroup>
  64.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  65.   </ItemGroup>}  <ItemGroup>
  66.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  67.   </ItemGroup>  <ItemGroup>
  68.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  69.   </ItemGroup>  <ItemGroup>
  70.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  71.   </ItemGroup>  <ItemGroup>
  72.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  73.   </ItemGroup>[Foo]  <ItemGroup>
  74.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  75.   </ItemGroup>  <ItemGroup>
  76.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  77.   </ItemGroup>public class F3  <ItemGroup>
  78.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  79.   </ItemGroup>  <ItemGroup>
  80.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  81.   </ItemGroup>{  <ItemGroup>
  82.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  83.   </ItemGroup>  <ItemGroup>
  84.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  85.   </ItemGroup>}  <ItemGroup>
  86.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  87.   </ItemGroup>    }  <ItemGroup>
  88.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  89.   </ItemGroup>    """;
复制代码
如上面代码所示,添加了一个放在 FooChunecilarkenaLibeewhemke 定名空间下的用于捣乱的 F3 类型,这个 F3 类型实际上标志的是 FooChunecilarkenaLibeewhemke.FooAttribute 特性,而不是源代码生成器盼望的标志了 Lindexi.FooAttribute 特性
尝试调试此单元测试代码,在语义判断处打上断点

此时可见在语义判断层面上进入了 if (!attributeDataArray.Any(t => t.AttributeClass?.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) == "global:indexi.FooAttribute")) 判断分支,这就意味着前面的语法判断过程中是放过了 F3 类型这个情况,只有在语义过程中,获取其全名才拿到了真实的名为 global::FooChunecilarkenaLibeewhemke.FooAttribute 的全名,从而将其过滤掉。符合预期的就是只输出 F1 和 F2 类型,过滤掉 F3 类型。咱可以在单元测试里面,为生成的代码添加固定测试,确保在变更逻辑的时候,如果有生成代码逻辑变动可以举行拦截。如以下代码所示
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>driver = driver.RunGenerators(compilation);  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>foreach (var generatedTree in driver.GetRunResult().GeneratedTrees)  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>{  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>    var generatedCode = generatedTree.ToString();  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>    Debug.WriteLine(generatedCode);  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>    if (generatedTree.FilePath.EndsWith("GeneratedCode.cs"))  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>    {  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>var expected =  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>    """  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>     using System;  <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>  <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>     namespace ChunecilarkenaLibeewhemke  <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>  <ItemGroup>
  36.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  37.   </ItemGroup>     {  <ItemGroup>
  38.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  39.   </ItemGroup>  <ItemGroup>
  40.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  41.   </ItemGroup>  <ItemGroup>
  42.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  43.   </ItemGroup> public static class GeneratedCode  <ItemGroup>
  44.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  45.   </ItemGroup>  <ItemGroup>
  46.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  47.   </ItemGroup>  <ItemGroup>
  48.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  49.   </ItemGroup> {  <ItemGroup>
  50.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  51.   </ItemGroup>  <ItemGroup>
  52.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  53.   </ItemGroup>  <ItemGroup>
  54.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  55.   </ItemGroup>     public static void Print()  <ItemGroup>
  56.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  57.   </ItemGroup>  <ItemGroup>
  58.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  59.   </ItemGroup>  <ItemGroup>
  60.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  61.   </ItemGroup>     {  <ItemGroup>
  62.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  63.   </ItemGroup>  <ItemGroup>
  64.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  65.   </ItemGroup>  <ItemGroup>
  66.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  67.   </ItemGroup>  <ItemGroup>
  68.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  69.   </ItemGroup> Console.WriteLine("标记了 Foo 特性的类型有: F1,F2,");  <ItemGroup>
  70.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  71.   </ItemGroup>  <ItemGroup>
  72.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  73.   </ItemGroup>  <ItemGroup>
  74.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  75.   </ItemGroup>     }  <ItemGroup>
  76.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  77.   </ItemGroup>  <ItemGroup>
  78.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  79.   </ItemGroup>  <ItemGroup>
  80.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  81.   </ItemGroup> }  <ItemGroup>
  82.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  83.   </ItemGroup>  <ItemGroup>
  84.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  85.   </ItemGroup>     }  <ItemGroup>
  86.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  87.   </ItemGroup>  <ItemGroup>
  88.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  89.   </ItemGroup>    """;  <ItemGroup>
  90.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  91.   </ItemGroup>  <ItemGroup>
  92.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  93.   </ItemGroup>// 防止拉取 git 时出现的 \r\n 不匹配问题。能够办理一些拉取 git 的奇怪的坑,也就是在我电脑上跑的好好的,但为什么在你电脑上就炸了  <ItemGroup>
  94.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  95.   </ItemGroup>  <ItemGroup>
  96.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  97.   </ItemGroup>expected = expected.Replace("\r\n", "\n");  <ItemGroup>
  98.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  99.   </ItemGroup>  <ItemGroup>
  100.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  101.   </ItemGroup>Assert.AreEqual(expected, generatedCode.Replace("\r\n", "\n"));  <ItemGroup>
  102.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  103.   </ItemGroup>    }  <ItemGroup>
  104.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  105.   </ItemGroup>}
复制代码
通过此单元测试也可以让大家更好地理解语法和语义上的差别,也能够让大家知道为什么尽管通过了语法判断,还必要语义举行兜底的缘故原由。在 C# 语法上,是可以存在局部代码完全相同,每个字符都相同,但实际上其语义是不相同的情况,必要联系其上下文才能知道。语法过程中更加关注语法本身,语义过程中才能从全局角度了解代码的语义
本章的代码放在 githubgitee 上,可以使用如下命令行拉取代码。我整个代码堆栈比力庞大,使用以下命令行可以举行部分拉取,拉取速率比力快
先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
  1. git init
  2. git remote add origin https://gitee.com/lindexi/lindexi_gd.git
  3. git pull origin abe3f751fe987a29d0b241501fade1d20c2dc74a
复制代码
以上使用的是国内的 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继承输入以下代码,将 gitee 源换成 github 源举行拉取代码。如果依然拉取不到代码,可以发邮件向我要代码
  1. git remote remove origin
  2. git remote add origin https://github.com/lindexi/lindexi_gd.git
  3. git pull origin abe3f751fe987a29d0b241501fade1d20c2dc74a
复制代码
获取代码之后,进入 Roslyn/ChunecilarkenaLibeewhemke 文件夹,即可获取到源代码
直接调试项目

在上一章中,和大家介绍了如何编写单元测试。在此过程中,也许有些伙伴会感觉编写单元测试还是比力繁琐的。大概说在编写单元测试的过程里面会比力耗时,纯字符串方式也没有代码提示,不太适合很多伙伴的工作现状。在大型项目中,或比力正式的项目里面,添加单元测试来提升分析器的稳定性,以及通过更多单元测试测试更多分支。而在许多没有那么多资源可以投入的情况下,则可以寻求简单的直接调试项目
简单的直接调试项目标方式指的是直接从分析器项目上,在 VisualStudio 里面一键 F5 就可以启动调试,调试入口和其他任何 dotnet 项目相同,非常方便。不必要去新建一个单元测试项目,可以直接对着目标项目,即被分析项目,举行调试。可以减少在单元测试里面搭建项目引用关系,搭建项目组织等的工作量
直接调试要求 Visual Studio 安装好了 .NET Compiler Platform SDK 负载组件,这个组件是用于支持 Roslyn 的调试情况。给 Visual Studio 打上 .NET Compiler Platform SDK 负载组件方法如下:

  • 运行“Visual Studio 安装程序”
  • 选择“修改”
  • 检查“Visual Studio 扩展开发”工作负荷。
  • 在摘要树中打开“Visual Studio 扩展开发”节点。
  • 选中“.NET Compiler Platform SDK”框。 将在可选组件最下面找到它


依然是为了让大家方便获取精确的代码起见,我这里继承新建两个项目,分别是名为 JehairqogefaKaiwuwhailallkihaiki.Analyzer 的分析器项目和名为 JehairqogefaKaiwuwhailallkihaiki 的被分析的控制台项目
这两个项目标代码不重要,大家可以使用上文 “更底层的收集分析和生成” 章节的代码。咱重点方在关注如何搭建调试上。大家可以开始对比一下本章介绍的直接调试项目标方法和上文介绍的搭建单元测试举行调试的方法,两个方法之间的便利性。在本身的项目里面选择合适的方式。大概是在项目刚开始的时候选用直接调试项目标方法,在项目成熟过程中再添加单元测试提升其稳定性
直接调试项目标方法的准备工作要求只有两点:

  • 确保分析器项目精确标志了 IsRoslynComponent 属性。即在分析器项目标 csproj 项目文件的 PropertyGroup 里面存在 true 代码片段。这个属性是告诉 VisualStudio 这是一个 Roslyn 组件,从而可以在调试的时候启动 Roslyn 的调试情况
  • 确保被调试项目精确添加了分析器项目引用,配置了 OutputItemType="Analyzer" 方式的引用
以下为分析器项目和被分析的控制台项目标 csproj 项目文件内容,大家可以对比一下本身的项目是否符合要求
分析器项目:
  1.       netstandard2.0    latest    true    true  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>  
复制代码
被分析的控制台项目:
  1. <Project Sdk="Microsoft.NET.Sdk">
  2.   <PropertyGroup>
  3.     <OutputType>Exe</OutputType>
  4.     <TargetFramework>net9.0</TargetFramework>
  5.     <ImplicitUsings>enable</ImplicitUsings>
  6.     <Nullable>enable</Nullable>
  7.   </PropertyGroup>
  8.   <ItemGroup>
  9.     <ProjectReference Include="..\DercelgefarKarhelchaye.Analyzer\DercelgefarKarhelchaye.Analyzer.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
  10.   </ItemGroup>
  11. </Project>
复制代码
准备工作完成之后,即可开始进入配置调试启动工作。我将会先告诉大家如何举行手工配置,再告诉大家如何举行图形化配置。以下是手工配置的部分
手工配置

在分析器项目上新建 Properties\launchSettings.json 调试启动配置文件。即在 Properties 文件夹里新建名为 launchSettings.json 的配置文件

在Properties\launchSettings.json 调试启动配置文件里面设置 DebugRoslynComponent 为 commandName 内容。将要被调试的 JehairqogefaKaiwuwhailallkihaiki 控制台项目相对路径设置到 targetProject 属性里面,其文件代码如下
  1. {
  2.   "profiles":
  3.   {
  4.     "JehairqogefaKaiwuwhailallkihaiki.Analyzer":
  5.     {
  6.       "commandName": "DebugRoslynComponent",
  7.       "targetProject": "..\\JehairqogefaKaiwuwhailallkihaiki\\JehairqogefaKaiwuwhailallkihaiki.csproj"
  8.     }
  9.   }
  10. }
复制代码
完成这些步调之后,手工配置部分就完成了,即可愉快的在分析器项目打上断点,设置分析器项目为启动项目,然后直接在 Visual Studio 使用 F5 一键运行启动调试分析器项目
如果大家发现本身的项目无法举行愉快的调试,可以尝试拉取我的代码用来测试和对比不同
以上代码放在 githubgitee 上,可以使用如下命令行拉取代码。我整个代码堆栈比力庞大,使用以下命令行可以举行部分拉取,拉取速率比力快
先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
  1. git init
  2. git remote add origin https://gitee.com/lindexi/lindexi_gd.git
  3. git pull origin c0e948b2a3aab521f2d6d86593c385f4d406cfa5
复制代码
以上使用的是国内的 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继承输入以下代码,将 gitee 源换成 github 源举行拉取代码。如果依然拉取不到代码,可以发邮件向我要代码
  1. git remote remove origin
  2. git remote add origin https://github.com/lindexi/lindexi_gd.git
  3. git pull origin c0e948b2a3aab521f2d6d86593c385f4d406cfa5
复制代码
获取代码之后,进入 Roslyn/JehairqogefaKaiwuwhailallkihaiki 文件夹,即可获取到源代码
图形化的配置方式

有伙伴说每次都必要新建 launchSettings.json 文件,要写相对的项目路径,这一点都不工程化,盼望能够有更加方便的做法。我接下来将和大家介绍更加 UI 图形化的配置方式
开始配置之前,请确保分析器项目精确配置了 IsRoslynComponent 属性,和被调试项目精确添加了分析器项目引用,配置了 OutputItemType="Analyzer" 属性。细节配置还请参考上文的准备工作部分
本文使用的 Visual Studio 为 Visual Studio 2022 17.12.4 版本。如果你的 Visual Studio 版本和我的差距过远,那可能以下图形界面或选项都有比力多的变更。这也就是为什么我选择先和大家介绍手工配置的缘故原由
配置步调如下:
先在 办理方案资源管理器 里面右击分析器项目,点击 设为启动项目 选项,将分析器项目设置为启动项目
再点击分析器项目标调试属性,如下图所示

在打开的启动配置文件窗口里面,找个命令行参数,任意写入点字符。这个过程仅仅只是为了让 VisualStudio 资助咱快速创建 launchSettings.json 文件而已。我现在还没有找到比这个方法更加顺手便捷的方式哈

双击 Properties\launchSettings.json 文件进入编辑,现在可见的 launchSettings.json 文件的内容大概如下
  1. {
  2.   "profiles":
  3.   {
  4.     "JehairqogefaKaiwuwhailallkihaiki.Analyzer":
  5.     {
  6.       "commandName": "Project",
  7.       "commandLineArgs": "123"
  8.     }
  9.   }
  10. }
复制代码
此时将 commandName 属性的 Project 内容换成 DebugRoslynComponent 内容,再删除 commandLineArgs 等其他属性。此时先不要写 targetProject 属性项,因为这个属性项要写相对路径,手写太烦了。编辑完成之后的 launchSettings.json 文件的内容大概如下
  1. {
  2.   "profiles":
  3.   {
  4.     "JehairqogefaKaiwuwhailallkihaiki.Analyzer":
  5.     {
  6.       "commandName": "DebugRoslynComponent"
  7.     }
  8.   }
  9. }
复制代码
继承点击分析器项目标调试属性,此时可见启动配置文件窗口界面如下

愉快点击下拉菜单,选择要调试项目即可,如下图所示

选中之后的结果如下图所示

完成之后,再次打开 launchSettings.json 文件,可以看到机智的 Visual Studio 已经帮咱填充了 targetProject 属性内容了。通过 Visual Studio 的填充,可以让咱不必要写繁琐的相对路径,也不用担心写错项目路径导致调试出错
  1. {
  2.   "profiles":
  3.   {
  4.     "JehairqogefaKaiwuwhailallkihaiki.Analyzer":
  5.     {
  6.       "commandName": "DebugRoslynComponent",
  7.       "targetProject": "..\\JehairqogefaKaiwuwhailallkihaiki\\JehairqogefaKaiwuwhailallkihaiki.csproj"
  8.     }
  9.   }
  10. }
复制代码
如此就完成了配置工作
如配置完成运行失败,提示无法启动调试 0x80070057 错误,办理方法请参阅 dotnet 在 VisualStudio 一键 F5 启动调试 Roslyn 分析器项目
使用语法可视化窗格辅助了解语法

有些伙伴会感觉即使在有上文的调试方法辅助的情况下,编写语法分析还是太复杂了,不知道怎么写。本身对语法分析本身也不熟悉,不知道可以如何编写语法分析的代码。这个时候可以使用视觉辅助了解语法
在 Visual Studio 里面自带了语法可视化(Syntax Visualizer)功能,可以资助大家更加直观的了解代码的语法树。在 Visual Studio 里面打开一个 C# 文件,然后在菜单栏里面点击 View(视图) -> Other Windows(其他窗口) -> Syntax Visualizer 打开语法可视化窗格,如下图所示

其界面大概如下

如果没有从视图里面找到 Syntax Visualizer 语法可视化窗格,则必要给 Visual Studio 打上 .NET Compiler Platform SDK 负载。正常来说,根据上文的步调一步步来的伙伴,都在前面准备直接调试的过程里面已经安装好了这个负载。安装方法如下:

  • 运行“Visual Studio 安装程序”
  • 选择“修改”
  • 检查“Visual Studio 扩展开发”工作负荷。
  • 在摘要树中打开“Visual Studio 扩展开发”节点。
  • 选中“.NET Compiler Platform SDK”框。 将在可选组件最下面找到它
详细安装方法请参阅 使用 Visual Studio 中的 Roslyn 语法可视化工具欣赏代码 - C# - Microsoft Learn 官方文档
回顾语法可视化窗格界面,可以看到有多个颜色标注出来不同的语法节点,如下图所示


  • 蓝色:SyntaxNode,表示声明、语句、子句和表达式等语法构造。
  • 绿色:SyntaxToken,表示关键字、标识符、运算符等标点。
  • 赤色:SyntaxTrivia,代表语法上不重要的信息,例如标志、预处置惩罚指令和解释之间的空格。
通过对照语法可视化窗格,可以更加直观的了解代码的语法树结构,从而更好的编写语法分析代码。在编写语法分析代码的时候,可以通过语法可视化窗格辅助了解语法,更加直观的了解代码的语法树结构,根据语法树结构编写语法分析代码
更多关于使用 Visual Studio 的语法可视化(Syntax Visualizer)窗格方法,请参阅:
Roslyn 入门:使用 Visual Studio 的语法可视化(Syntax Visualizer)窗格查看和了解代码的语法树 - walterlv
演练:写一个类型收集器

学习了这么多,可以试试举行一些实践演练。在本次演练里面我将会告诉大家更多基础知识,以及分析器的一些计划思想
演练任务

在上文里面和大家介绍了如何举行类型的收集,在本次演练中,将继承加一点需求:让收集到的类型可以同时生成创建器,创建器里面要求传入上下文参数。这是一个很典型的容器注入的需求,不熟悉容器的伙伴也没关系,我用具体的代码来更具体地说明的任务需求
假定有 F1 和 F2 和 F3 三个类型,其界说代码分别如下
  1. public interface IFoo{}public class F1: IFoo{    public F1(IContext context)    {  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>// 忽略其他代码    }}public class F2 : IFoo{    public F2(IContext context)    {  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>// 忽略其他代码    }}public class F3 : IFoo{    public F3(IContext context)    {  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>// 忽略其他代码    }}public interface IContext{    // 忽略其他代码}
复制代码
预期能够通过源代码生成器生成收集器的代码,其代码预期内容大概如下
  1. public static partial class FooCollection{    [Collection]    public static partial IEnumerable GetFooCreatorList()    {  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>yield return context => new F1(context);  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>yield return context => new F2(context);  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>yield return context => new F3(context);    }}
复制代码
以上的 FooCollection 的 GetFooCreatorList 方法就是咱源代码生成器的生成任务内容。这是一个知识内容比力综合的演练。我将在这个演练里面和大家演示源代码生成器的日常食用方法
假定现在用户已经界说好了 F1 和 F2 和 F3 三个类型,被其继承的 IFoo 接口和用作参数的 IContext 接口,以及如下代码所示的 FooCollection 的分部 GetFooCreatorList 方法。源代码生成器必要生成 CollectionAttribute 特性类型的代码,以及 FooCollection 的 GetFooCreatorList 分部方法的具体实现代码
  1. public static partial class FooCollection
  2. {
  3.     [Collection]
  4.     public static partial IEnumerable<Func<IContext, IFoo>> GetFooCreatorList();
  5. }
复制代码
咱必要做的就是源代码生成器部分的逻辑,这个过程中再加点更多需求,那就是尽可能让 Visual Studio 用的开森,以及在遇到不符合预期的代码时给淘气的开发者报告一些告诫信息
演练步调

整体的步调可以分为以下几个步调:

  • 生成 CollectionAttribute 特性类型的代码
  • 分析使用了 CollectionAttribute 特性的分部方法,且找到方法的返回值参数
  • 根据返回值参数的类型,遍历收集项目标类型,找到感爱好的类型,生成创建器代码
依然是为了方便大家获取到精确的源代码,我这里重新创建两个项目,分别是名为 KawhawnahemCanalllearlerwhu 的控制台项目,以及名为 KawhawnahemCanalllearlerwhu.Analyzer 的分析器项目。这两个项目标初始化搭建和上文的章节一样,不再赘述。大家可以直接使用上文的章节的代码举行初始化搭建
完成项目搭建之后,就可以开始进入本次演练的步调了
演练内容里面只给出关键代码片段,如必要全部的项目文件,可到本章末尾找到所有代码的拉取下载方法
生成特性类型的代码

生成 CollectionAttribute 特性类型的代码部分,可以参考上文的章节,这里不再赘述。直接使用 RegisterPostInitializationOutput 方法注册生成 CollectionAttribute 特性类型的代码
  1. using System;using System.Buffers;using System.Collections.Generic;using System.Collections.Immutable;using System.Diagnostics;using System.Linq;using System.Text;using System.Threading;using KawhawnahemCanalllearlerwhu.Analyzer.Properties;using Microsoft.CodeAnalysis;using Microsoft.CodeAnalysis.CSharp;using Microsoft.CodeAnalysis.CSharp.Syntax;namespace KawhawnahemCanalllearlerwhu.Analyzer;[Generator(LanguageNames.CSharp)]public class FooIncrementalGenerator : IIncrementalGenerator{    public void Initialize(IncrementalGeneratorInitializationContext context)    {  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>context.RegisterPostInitializationOutput(initializationContext =>  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>{  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>    initializationContext.AddSource("CollectionAttribute.cs",  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>"""  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>namespace Lindexi;  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>internal class CollectionAttribute : Attribute  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>{  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>}  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>  <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>""");  <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>});  <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>... // 忽略其他代码    }}
复制代码
以上代码唯一的细节是设置 CollectionAttribute 为 internal 类型,这样就可以保证 CollectionAttribute 只能在当前项目内部使用,不会被外部项目引用到。如此能够规避多个相互引用的项目同时使用了此分析器,导致生成了多个相同定名空间的 CollectionAttribute 类型的问题
分析使用了 CollectionAttribute 特性的分部方法

使用上文章节的 ForAttributeWithMetadataName 方法找到标志了 CollectionAttribute 特性的方法。这里必要说明的是 ForAttributeWithMetadataName 方法不但可以用来找类型,还可以用来找其他可以标志特性的成员,自然也包括方法
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>    context.SyntaxProvider.ForAttributeWithMetadataName  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>    (  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>"Lindexi.CollectionAttribute", static (SyntaxNode node, CancellationToken _) =>  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>{  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>    if (node is MethodDeclarationSyntax methodDeclarationSyntax)  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>    {  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>// 判断是否是 partial 分部方法  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>  <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>  <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>return methodDeclarationSyntax.Modifiers.Any(t => t.IsKind(SyntaxKind.PartialKeyword));  <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>  <ItemGroup>
  36.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  37.   </ItemGroup>    }  <ItemGroup>
  38.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  39.   </ItemGroup>  <ItemGroup>
  40.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  41.   </ItemGroup>    return false;  <ItemGroup>
  42.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  43.   </ItemGroup>  <ItemGroup>
  44.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  45.   </ItemGroup>},  <ItemGroup>
  46.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  47.   </ItemGroup>  <ItemGroup>
  48.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  49.   </ItemGroup>(GeneratorAttributeSyntaxContext syntaxContext, CancellationToken _) =>  <ItemGroup>
  50.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  51.   </ItemGroup>  <ItemGroup>
  52.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  53.   </ItemGroup>{  <ItemGroup>
  54.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  55.   </ItemGroup>  <ItemGroup>
  56.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  57.   </ItemGroup>    ... // 忽略其他代码  <ItemGroup>
  58.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  59.   </ItemGroup>  <ItemGroup>
  60.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  61.   </ItemGroup>}  <ItemGroup>
  62.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  63.   </ItemGroup>    );
复制代码
在 C# dotnet 里面的分部方法的计划上,可以让源代码生成器和 IDE 都非常开森。其缘故原由是在 IDE 的视角上,分部方法已经完成了整个方法的对外界说。对于其他外部的引用来说,已经满足了基础的符号关系。毕竟对于外部引用来说,具体方法里面的实现是完全不关心的。只要有方法界说,就可以完全创建符号关系。这就意味着具体分部方法的实现代码,可以慢慢让源代码生成器来生成,在源代码生成器生成的过程中,IDE 也不会有任何的报错飘红。对源代码生成器来说,分部方法是一个非常好的锚点,特殊是加上标志了特性的分部方法。这就是为什么现在很多 dotnet 基础支持上,都推荐写分部方法标志特性来实现很多功能的缘故原由,比如以下代码演示的 GeneratedRegex 正则表达式源生成器方法
  1. [GeneratedRegex("abc|def", RegexOptions.IgnoreCase, "en-US")]private static partial Regex AbcOrDefGeneratedRegex();private static void EvaluateText(string text){    if (AbcOrDefGeneratedRegex().IsMatch(text))    {  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>// Take action with matching text    }}
复制代码
以上代码为 dotnet 内建机制,可以有效生成高速的 Regex 代码,极大提升整体性能,避免运行时编正则带来的损耗,如对此细节感爱好,请参阅 .NET 正则表达式源生成器 - .NET - Microsoft Learn
以上举例的 AbcOrDefGeneratedRegex 仅仅只是歪楼告诉大家,分部方法配合特性,让源代码生成器填充具体实现内容是现在 dotnet 的惯用方法而已。举例的 AbcOrDefGeneratedRegex 以及正则内容和本文内容没有直接关联
在 ForAttributeWithMetadataName 的语义转换步调里面,将获取其分部方法的返回值类型,以及在此同时生成部分代码
获取分部方法的返回值类型,可以通过以下代码获取
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>context.SyntaxProvider.ForAttributeWithMetadataName  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>(  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>    "Lindexi.CollectionAttribute", static (SyntaxNode node, CancellationToken _) =>  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>    {  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>... // 忽略其他代码  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>    },  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>  <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>    (GeneratorAttributeSyntaxContext syntaxContext, CancellationToken _) =>  <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>  <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>    {  <ItemGroup>
  36.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  37.   </ItemGroup>  <ItemGroup>
  38.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  39.   </ItemGroup>  <ItemGroup>
  40.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  41.   </ItemGroup>var methodSymbol = (IMethodSymbol)syntaxContext.TargetSymbol;  <ItemGroup>
  42.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  43.   </ItemGroup>  <ItemGroup>
  44.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  45.   </ItemGroup>  <ItemGroup>
  46.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  47.   </ItemGroup>if (!methodSymbol.IsPartialDefinition)  <ItemGroup>
  48.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  49.   </ItemGroup>  <ItemGroup>
  50.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  51.   </ItemGroup>  <ItemGroup>
  52.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  53.   </ItemGroup>{  <ItemGroup>
  54.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  55.   </ItemGroup>  <ItemGroup>
  56.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  57.   </ItemGroup>  <ItemGroup>
  58.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  59.   </ItemGroup>    return null;  <ItemGroup>
  60.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  61.   </ItemGroup>  <ItemGroup>
  62.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  63.   </ItemGroup>  <ItemGroup>
  64.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  65.   </ItemGroup>}  <ItemGroup>
  66.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  67.   </ItemGroup>  <ItemGroup>
  68.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  69.   </ItemGroup>  <ItemGroup>
  70.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  71.   </ItemGroup>ITypeSymbol returnType = methodSymbol.ReturnType;  <ItemGroup>
  72.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  73.   </ItemGroup>  <ItemGroup>
  74.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  75.   </ItemGroup>  <ItemGroup>
  76.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  77.   </ItemGroup>// 这是一个泛型类型,我们必要获取泛型参数  <ItemGroup>
  78.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  79.   </ItemGroup>  <ItemGroup>
  80.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  81.   </ItemGroup>  <ItemGroup>
  82.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  83.   </ItemGroup>// 预期是 IEnumerable 这样的类型  <ItemGroup>
  84.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  85.   </ItemGroup>  <ItemGroup>
  86.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  87.   </ItemGroup>  <ItemGroup>
  88.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  89.   </ItemGroup>if (returnType is not INamedTypeSymbol methodSymbolReturnType)  <ItemGroup>
  90.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  91.   </ItemGroup>  <ItemGroup>
  92.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  93.   </ItemGroup>  <ItemGroup>
  94.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  95.   </ItemGroup>{  <ItemGroup>
  96.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  97.   </ItemGroup>  <ItemGroup>
  98.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  99.   </ItemGroup>  <ItemGroup>
  100.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  101.   </ItemGroup>    return null;  <ItemGroup>
  102.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  103.   </ItemGroup>  <ItemGroup>
  104.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  105.   </ItemGroup>  <ItemGroup>
  106.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  107.   </ItemGroup>}  <ItemGroup>
  108.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  109.   </ItemGroup>  <ItemGroup>
  110.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  111.   </ItemGroup>  <ItemGroup>
  112.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  113.   </ItemGroup>... // 忽略其他代码  <ItemGroup>
  114.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  115.   </ItemGroup>  <ItemGroup>
  116.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  117.   </ItemGroup>    });
复制代码
在获取到返回值类型之后,必要进一步判断返回值类型是否符合预期,代码如下
  1. ITypeSymbol returnType = methodSymbol.ReturnType; // 这是一个泛型类型,我们必要获取泛型参数 // 预期是 IEnumerable 这样的类型 if (returnType is not INamedTypeSymbol methodSymbolReturnType) {     return null; } var fullNameDisplayFormat = new SymbolDisplayFormat (     // 带上定名空间和类型名     SymbolDisplayGlobalNamespaceStyle.Included,     // 定名空间之前加上 global 防止辩论     SymbolDisplayTypeQualificationStyle  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup> .NameAndContainingTypesAndNamespaces ); var returnTypeName = methodSymbolReturnType.ToDisplayString(fullNameDisplayFormat); // 预期的返回值类型 const string exceptedReturnTypeName = "global::System.Collections.Generic.IEnumerable"; if (!string.Equals(returnTypeName, exceptedReturnTypeName, StringComparison.InvariantCulture)) {     return null; }
复制代码
以上代码使用的是让返回值类型输出为全名的方式举行判断,这样的判断方式可以避免存在重名的情况。在判断返回值类型符合预期之后,继承取出其泛型里面的类型
  1. if (methodSymbolReturnType.TypeArguments.Length != 1)
  2. {
  3.      // 预期是 IEnumerable<Func> 这样的类型,在 IEnumerable 里面只有一个泛型参数
  4.      return null;
  5. }
  6. // 取出 IEnumerable<Func<IContext, IFoo>> 中的 Func<IContext, IFoo> 部分
  7. if (methodSymbolReturnType.TypeArguments[0] is not INamedTypeSymbol funcTypeSymbol)
  8. {
  9.      return null;
  10. }
复制代码
同理,拿到了 funcTypeSymbol 变量也要判断一下是否 System.Func 类型,以及判断其参数是否符合预期
  1. // 取出 IEnumerable<Func<IContext, IFoo>> 中的 Func<IContext, IFoo> 部分
  2. if (methodSymbolReturnType.TypeArguments[0] is not INamedTypeSymbol funcTypeSymbol)
  3. {
  4.     return null;
  5. }
  6. const string exceptedFuncTypeName = "global::System.Func";
  7. var funcTypeName = funcTypeSymbol.ToDisplayString(fullNameDisplayFormat);
  8. if (!string.Equals(funcTypeName, exceptedFuncTypeName, StringComparison.InvariantCulture))
  9. {
  10.     // 如果不是 Func 类型的,则不是预期的
  11.     return null;
  12. }
  13. // 继续取出 Func<IContext, IFoo> 中的 IContext 和 IFoo 部分
  14. if (funcTypeSymbol.TypeArguments.Length != 2)
  15. {
  16.     return null;
  17. }
复制代码
写了这么长的判断,实在只是为了判断是否 IEnumerable 类型返回值,以及取出 IContext 作为参数类型和 IFoo 作为返回值类型。虽然代码看起来很长,但相信大家能够很快理解
以下为取出 IContext 作为参数类型和 IFoo 作为返回值类型的代码,后续逻辑将必要用到这两个类型的语义
  1. // 取出 Func<IContext, IFoo> 中的 IContext 部分
  2. ITypeSymbol constructorArgumentType = funcTypeSymbol.TypeArguments[0];
  3. string constructorArgumentTypeName = constructorArgumentType.ToDisplayString(fullNameDisplayFormat);
  4. // 取出 Func<IContext, IFoo> 中的 IFoo 部分
  5. ITypeSymbol collectionType = funcTypeSymbol.TypeArguments[1];
  6. var collectionTypeName = collectionType.ToDisplayString(fullNameDisplayFormat);
复制代码
以上代码在取出的过程中,顺带也获取类型的全名,这在后续的代码生成过程中会用到。在这个步调里面就立即生成了部分的代码。这是因为在这里举行生成,可以省去将当前的 IMethodSymbol 传递到后续的代码生成过程中,提升不到一分钱的性能
在 ForAttributeWithMetadataName 的 transform 过程中,作为返回值的内容,都会参与到缓存的计算中。在增量源代码生成计划里面,通过大量的缓存换取减少计算的时间。但缓存本身会涉及很多相称判断逻辑,传递 IMethodSymbol 等符号对象在判断中会比传递字符串更加昂贵,这就是为什么马上在此举行消耗的缘故原由。但这里必要取得一个均衡点,更多发出转换器的代码,而不要在一个转换器里面写太多逻辑,减少变更代码过程中的无效逻辑处置惩罚,防止跑了一大堆逻辑但最终因为代码文件内容变更而无效的情况
在本演练例子里面,只是举行部分代码生成,这个过程还是不到一分钱的
在这里盼望生成的代码的示例内容
  1. // 生成的代码的示例内容namespace KawhawnahemCanalllearlerwhu;public static partial class FooCollection{    public static partial IEnumerable GetFooCreatorList()    {  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>yield return context => new F1(context);  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>yield return context => new F2(context);  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>yield return context => new F3(context);    }}
复制代码
固然了,其中间的 yield return context => new F1(context); 等代码,现在还不能生成,因为还没举行项目标类型收集。这个过程将在下一步举行。在这里只生成这个空壳的方法代码框架
生成这个空壳框架代码必要获取到分部方法所在的类型、类型所在的定名空间,分部方法的名称、访问修饰符、是否静态等信息,准备工作如下代码所示
  1. INamedTypeSymbol containingType = methodSymbol.ContainingType; string classNamespace = containingType.ContainingNamespace.Name; string className = containingType.Name; // Modifiers Accessibility declaredAccessibility = containingType.DeclaredAccessibility; var modifier = AccessibilityToString(declaredAccessibility);      static string AccessibilityToString(Accessibility accessibility)  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>=> accessibility switch  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>{  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>    Accessibility.Public => "public",  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>    Accessibility.Protected => "protected",  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>    // 不写了,省略。大家有空本身增补  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>    _ => string.Empty,  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>};
复制代码
其拼接的生成的空壳方法框架的代码如下
  1. var generatedCode =  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>$$"""  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>  namespace {{classNamespace}};  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>  {{modifier}}{{(containingType.IsStatic ? " static" : "")}} partial class {{className}}  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>  {  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>      {{AccessibilityToString(methodSymbol.DeclaredAccessibility)}}{{(methodSymbol.IsStatic ? " static" : "")}} partial {{exceptedReturnTypeName}}  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>  {{methodSymbol.Name}}()  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>      {  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>  yield return context => new F1(context);  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>      }  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>  }  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>  """    ;
复制代码
注: 为了让我的博客引擎开森,以上代码部分花括号被我替换为了全角花括号。大家在使用的时候必要将全角花括号替换为半角花括号
以上空壳框架代码的 yield return context => new F1(context); 将在后续用作替换字符串的占位符,当前生成的代码内容,即 generatedCode 变量的字符串内容如下
  1. namespace KawhawnahemCanalllearlerwhu;public static partial class FooCollection{    public static partial global::System.Collections.Generic.IEnumerableGetFooCreatorList()    {  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>yield return context => new F1(context);    }}
复制代码
在源代码生成器的套路里面,就是尽量使用全定名空间,即带上 global:: 前缀,这样可以避免引用辩论。在这里的代码生成过程中,也是使用了全定名空间的方式,以保证生成的代码可以在任何地方使用。虽然这个方式会让生成的代码比力繁琐,但毕竟是呆板生成的代码,不必要人工去编写,只是会添加一些阅读的心智负担
如果感觉确实阅读不方便,那就在 using 处写明别名,带上全定名空间,如 using Xxx = global::Xx.Fxxx 之类的写法
为了在 ForAttributeWithMetadataName 的 transform 举行返回,这里界说一个名为 CollectionExportMethodInfo 的类型,用于存储过程信息,其代码如下
  1. record CollectionExportMethodInfo
  2. (
  3.     ITypeSymbol ConstructorArgumentType,
  4.     ITypeSymbol CollectionType,
  5.     GeneratedCodeInfo GeneratedCodeInfo,
  6.     Location Location
  7. );
  8. readonly record struct GeneratedCodeInfo(string GeneratedCode, string Name);
复制代码
在源代码生成器里面使用 record 或 readonly record struct 是非常舒坦的,因为记载类型自带了相称判断比力器,可以省去很多工作量。但在这里必要额外说明的是,默认的相称比力器对符号类型来说是不够正确的,故意的源代码生成器开发者可以对以上的 CollectionExportMethodInfo 类型举行更加正确的相称比力器的重写,使用 SymbolEqualityComparer 比力器代替默认的相称比力器。这里的焦点缘故原由是 Roslyn 在计划之初时, C# 代码还没有可空的概念。于是计划上对类型只有一个概念,后续 NRT (Nullable Reference Types) 引入之后,导致了一个类型还有另一个可空概念,进而导致了判断逻辑上存在两个选项,分别是 SymbolEqualityComparer.Default 和 SymbolEqualityComparer.IncludeNullability 这两个选项。为了明白起见,于是 Roslyn 团队决定引入 SymbolEqualityComparer 比力器,从而可以让分析器开发者明白知道本身在做什么

  • SymbolEqualityComparer.Default 比力器是不包罗可空性的比力器,即不区分可空性的比力器。对 string 和 string? 举行相称比力,返回的结果是相称的。这个比力器是默认的比力器,与默认会调用的相称比力器行为相同。这就是为什么上述代码即使不重写相称比力器,在业务上也是精确的缘故原由
  • SymbolEqualityComparer.IncludeNullability 比力器是包罗可空性的比力器,即区分可空性的比力器。对 string 和 string? 举行相称比力,返回的结果是不相称的。这个比力器是为了让开发者明白知道本身在做什么,以及在必要区分可空性的情况下使用的比力器
  1. ISymbol? x = ...
  2. ISymbol? y = ...
  3. var defaultAreEquals = x.Equals(y); // Warn: RS1024 Symbols should be compared for equality
  4. var areEquals = SymbolEqualityComparer.Default.Equals(x, y); // string == string?
  5. // 或:
  6. var areEquals = SymbolEqualityComparer.IncludeNullability.Equals(x, y); // string != string?
复制代码
注: 更多关于 SymbolEqualityComparer 比力器与默认比力器的差别,请参阅此帖子: https://github.com/dotnet/roslyn-analyzers/issues/3427
完成 CollectionExportMethodInfo 的界说之后,将其作为返回值返回
  1. // 获取代码的位置,用于生成警告和错误。即告诉 Visual Studio 应该在哪里飘红
  2. var location = syntaxContext.TargetNode.GetLocation();
  3. // 使用 record 类型自带的相等判断,能够省心很多
  4. return new CollectionExportMethodInfo(constructorArgumentType, collectionType,
  5.     new GeneratedCodeInfo(generatedCode, $"{className}.{methodSymbol.Name}"), location);
复制代码
返回时,从 TargetNode 里面调用 GetLocation 获取到 Location 位置信息。此 Location 信息可用于后续生成告诫和错误信息,即告诉 Visual Studio 应该在哪里飘红。拿到的 Location 就是对应的代码的位置信息,如是哪个文件,哪个行号,从哪列到哪列等信息
由于在 ForAttributeWithMetadataName 语义分析过程中,还包罗了一些过滤条件,将不满足条件的,都使用 null 举行返回。于是在 ForAttributeWithMetadataName 方法完成返回时,再叠加 Where 条件,用于过滤掉不符合条件的情况。其代码如下
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>    var provider = context  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>    .SyntaxProvider.ForAttributeWithMetadataName  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>    (  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>"Lindexi.CollectionAttribute", static (SyntaxNode node, CancellationToken _) =>  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>{  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>    ... // 忽略其他代码  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>},  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>(GeneratorAttributeSyntaxContext syntaxContext, CancellationToken _) =>  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>  <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>{  <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>  <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>    ... // 忽略其他代码  <ItemGroup>
  36.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  37.   </ItemGroup>  <ItemGroup>
  38.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  39.   </ItemGroup>}  <ItemGroup>
  40.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  41.   </ItemGroup>    )  <ItemGroup>
  42.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  43.   </ItemGroup>    // 过滤掉不符合条件的情况  <ItemGroup>
  44.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  45.   </ItemGroup>    .Where(t => t != null);
复制代码
回顾本次演练的任务,在当前步调里面收集到的是一个个的标志了 CollectionAttribute 特性的分部方法,以及这些方法的返回值类型。敲黑板,这里收集到的是一个个的。这就意味着如果直接拿这一个个去与后续的全项目所有类型举行处置惩罚,则其处置惩罚次数会是 m * n 的量,这里的 m 是标志了 CollectionAttribute 特性的分部方法的数量,n 是全项目所有类型的数量。且这个触发不止一次,而是每次有代码变更都会触发。在 Roslyn 源代码生成器里面禁止此行为,只答应将 IncrementalValuesProvider 多值提供器与 IncrementalValueProvider 单值提供器举行 Combine 组合。禁止将 IncrementalValuesProvider 多值提供器与 IncrementalValuesProvider 多值提供器举行组合
这里有一个容易混淆的点,多值提供器与单值提供器,其类型分别如下:

  • IncrementalValuesProvider 多值提供器
  • IncrementalValueProvider 单值提供器
两者差异只是一个是 Values 而另一个是 Value 而已,即多了 s 的差别而已,两个单词比力好混哦
为了能够和后续的全项目类型收集举行 Combine 合并组合处置惩罚,这里在 Where 之后,再调用 Collect 方法,将其收集起来,成为 IncrementalValueProvider 单值提供器,代码如下
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>IncrementalValueProvider collectionMethodInfoProvider = context  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>    .SyntaxProvider.ForAttributeWithMetadataName(  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>"Lindexi.CollectionAttribute", static (SyntaxNode node, CancellationToken _) =>  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>{  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>    ... // 忽略其他代码  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>},  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>(GeneratorAttributeSyntaxContext syntaxContext, CancellationToken _) =>  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>{  <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>  <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>    ... // 忽略其他代码  <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>  <ItemGroup>
  36.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  37.   </ItemGroup>})  <ItemGroup>
  38.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  39.   </ItemGroup>    // 过滤掉不符合条件的情况  <ItemGroup>
  40.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  41.   </ItemGroup>    .Where(t => t != null)  <ItemGroup>
  42.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  43.   </ItemGroup>    .Collect()!;
复制代码
大家是否好奇,似乎这里的 IncrementalValueProvider 单值提供器也是骗人的,里面明显就是一个不可变数组,也就是里面就是一个集合。为什么这样也能称为单值提供器?因为多值和单值是从源代码生成器的缓存角度来说的。即数据提供器里面提供的是多个值还是单个值。这里的 IncrementalValueProvider 单值提供器,其提供的是一个集合,即一个值,所以称为单值提供器。焦点差异在于如代码变更的时候,应该刷新的范围是多大。对于 IncrementalValueProvider 来说,只要有一个标志了 CollectionAttribute 的符合条件的分部方法发生了变更,就会触发整个集合的刷新,即 collectionMethodInfoProvider 将会重新提供值
但对于 IncrementalValuesProvider 多值提供器来说,里面的每一项都是独立的,其中一项的变更,只有触发其对应的一次,而不会影响其他项的触发。这也就是为什么 Collect 的计划上不答应多值提供器与多值提供器举行组合的缘故原由。因为多值提供器与多值提供器组合,将会在某一项值变更的时候,其触发条件是比力震荡的,复杂度比力高,不但人类程序猿顶不住,呆板也顶不住
换句话说就是只要任意一个标志了 CollectionAttribute 的符合条件的分部方法发生了变更,就会触发整个 ImmutableArray 集合的刷新。但任意一个标志了 CollectionAttribute 的符合条件的分部方法发生了变更,走到 Where 处的变更也就只有这一个分部方法而已,只不过后续的 ImmutableArray 集合的刷新是靠 Collect 触发的。因为到 Where 处还是多值提供器,只有到 Collect 处才会酿成单值提供器
以上代码就完成了对标志了 CollectionAttribute 特性的分部方法的收集,分析使用了 CollectionAttribute 特性的分部方法,且找到方法的返回值参数,生成 CollectionAttribute 特性类型的代码。接下来将会在下一步根据返回值参数的类型,遍历收集全项目标类型,找到感爱好的类型,生成创建器代码
遍历收集全项目标类型,生成创建器代码

全项目类型收集过程里面将不能使用 ForAttributeWithMetadataName 方法,而是必要使用上文介绍的高度定制支持的更底层的收集分析的 CreateSyntaxProvider 方法。在语法层面,先判断是类型即可通过,本身就必要遍历全项目标类型的,自然判断语法是类型即可
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>IncrementalValuesProvider wholeAssemblyClassTypeProvider = context.SyntaxProvider.CreateSyntaxProvider(  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>    static (SyntaxNode node, CancellationToken _) => node.IsKind(SyntaxKind.ClassDeclaration),  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>    (GeneratorSyntaxContext syntaxContext, CancellationToken _) =>  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>    {  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>... // 忽略其他代码  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>    });
复制代码
语义层面上,由于现在还没有和对标志了 CollectionAttribute 特性的分部方法的收集的合并,在语义层面上也就没啥好判断的。最多只判断要求类型不能是抽象的,毕竟按照咱的需求任务来说,要的就是创建出对象,抽象类型就不能被直接创建啦,自然就可以被过滤掉
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>// 全项目里面的类型  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>IncrementalValuesProvider wholeAssemblyClassTypeProvider  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>    = context.SyntaxProvider  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>.CreateSyntaxProvider(  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>    static (SyntaxNode node, CancellationToken _) => node.IsKind(SyntaxKind.ClassDeclaration),  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>    static (GeneratorSyntaxContext generatorSyntaxContext, CancellationToken token) =>  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>    {  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>var classDeclarationSyntax = (ClassDeclarationSyntax) generatorSyntaxContext.Node;  <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>  <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>  <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>INamedTypeSymbol? assemblyClassTypeSymbol =  <ItemGroup>
  36.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  37.   </ItemGroup>  <ItemGroup>
  38.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  39.   </ItemGroup>  <ItemGroup>
  40.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  41.   </ItemGroup>    generatorSyntaxContext.SemanticModel.GetDeclaredSymbol(classDeclarationSyntax, token);  <ItemGroup>
  42.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  43.   </ItemGroup>  <ItemGroup>
  44.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  45.   </ItemGroup>  <ItemGroup>
  46.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  47.   </ItemGroup>if (assemblyClassTypeSymbol is not null && !assemblyClassTypeSymbol.IsAbstract)  <ItemGroup>
  48.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  49.   </ItemGroup>  <ItemGroup>
  50.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  51.   </ItemGroup>  <ItemGroup>
  52.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  53.   </ItemGroup>{  <ItemGroup>
  54.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  55.   </ItemGroup>  <ItemGroup>
  56.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  57.   </ItemGroup>  <ItemGroup>
  58.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  59.   </ItemGroup>    return assemblyClassTypeSymbol;  <ItemGroup>
  60.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  61.   </ItemGroup>  <ItemGroup>
  62.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  63.   </ItemGroup>  <ItemGroup>
  64.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  65.   </ItemGroup>}  <ItemGroup>
  66.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  67.   </ItemGroup>  <ItemGroup>
  68.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  69.   </ItemGroup>  <ItemGroup>
  70.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  71.   </ItemGroup>return null;  <ItemGroup>
  72.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  73.   </ItemGroup>  <ItemGroup>
  74.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  75.   </ItemGroup>    })  <ItemGroup>
  76.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  77.   </ItemGroup>  <ItemGroup>
  78.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  79.   </ItemGroup>.Where(t => t != null)!;
复制代码
完成了全项目类型的收集之后,就可以和收集了标志了 CollectionAttribute 特性的分部方法的 collectionMethodInfoProvider 举行合并,其代码如下
  1. wholeAssemblyClassTypeProvider
  2.     .Combine(collectionMethodInfoProvider)
复制代码
调用 Combine 之后返回的类型是一个元组,为 IncrementalValuesProvider 类型。即左边 Left 是多值提供器里面的每一个值,即项目里面的每个类型,右边是单值提供器里面的值
继承处置惩罚,带上 Select 方法,判断各自类型是否满足标志了 CollectionAttribute 特性的分部方法的感爱好条件
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>       wholeAssemblyClassTypeProvider  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>.Combine(collectionMethodInfoProvider)  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>.Select(static ((INamedTypeSymbol Left, ImmutableArray Right) tuple,  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>    CancellationToken token) =>  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>{  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>    INamedTypeSymbol assemblyClassTypeSymbol = tuple.Left;  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>    var exportMethodReturnTypeCollectionResultArray = tuple.Right;  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>  <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>    ... // 忽略其他代码  <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>  <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>})
复制代码
在这一步里面,咱可以激进一些,直接就干到生成了对应的项的代码里面,即生成如  yield return context => new Foo(context); 的代码。为了表示此返回类型,这里再次界说一个名为 ItemGeneratedCodeResult 的新的类型
  1. readonly record struct ItemGeneratedCodeResult
  2. (
  3.     string ItemGeneratedCode,
  4.     GeneratedCodeInfo ExportMethodGeneratedCodeInfo
  5. )
  6. {
  7.     public Diagnostic? Diagnostic { get; init; }
  8. }
复制代码
这个新的 ItemGeneratedCodeResult 类型采用的是 readonly record struct 的计划,这会让分析器更加开森。我感觉 readonly record struct 是非常舒坦的计划,不会担心这样的类型在大量使用中,会造成大量的堆对象分配,也不会担心其分配成本和 GC 压力。使用值类型的计划是在分析器官方里面所推荐的,如以下的官方文档所示
Use value types where possible: Value types are more amenable to caching and usually have well defined and easy to understand comparison semantics.
以上的 ItemGeneratedCodeResult 类型包罗了 Diagnostic 类型的 Diagnostic 属性,这是用于在举行源代码生成过程中,发现某些代码不符合预期,举行的分析告诫或错误信息。从这里也可以看出来源代码生成器本身也带有分析器的功能,这部分的具体使用将在下文介绍
由于 Right 是 ImmutableArray 类型,表示的所有的标志了 CollectionAttribute 的分部方法收集信息。因此这里咱也必要对应的创建一个列表,用于创建多对多的关系,即一个类型可能存在对应多个分部方法的关系
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>.Select(static ((INamedTypeSymbol Left, ImmutableArray Right) tuple,  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>    CancellationToken token) =>  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>{  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>    INamedTypeSymbol assemblyClassTypeSymbol = tuple.Left;  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>    var exportMethodReturnTypeCollectionResultArray = tuple.Right;  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>    // 慢点创建列表,因为这里是每个类型都会进入一次的,进入次数很多。但大部分类型都不满足条件。因此不提前创建列表能减少很多对象的创建  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>    List? result = null;  <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>  <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>    ... // 忽略其他代码  <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>  <ItemGroup>
  36.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  37.   </ItemGroup> })
复制代码
这里的 List? result 我选择不要一开始就创建,因为现在收集到的类型不一定会满足任何一个分部方法的要求,即这将是一个被忽略的类型。慢点创建可以减少浪费
遍历分部方法收集 ImmutableArray 数组,判断类型是否落在某个分部方法感爱好条件里面,代码如下
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>.Select(static ((INamedTypeSymbol Left, ImmutableArray Right) tuple,  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>    CancellationToken token) =>  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>{  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>    INamedTypeSymbol assemblyClassTypeSymbol = tuple.Left;  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>    var exportMethodReturnTypeCollectionResultArray = tuple.Right;  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>    // 慢点创建列表,因为这里是每个类型都会进入一次的,进入次数很多。但大部分类型都不满足条件。因此不提前创建列表能减少很多对象的创建  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>    List? result = null;  <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>  <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>    foreach (CollectionExportMethodInfo exportMethodInfo in exportMethodReturnTypeCollectionResultArray)  <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>  <ItemGroup>
  36.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  37.   </ItemGroup>    {  <ItemGroup>
  38.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  39.   </ItemGroup>  <ItemGroup>
  40.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  41.   </ItemGroup>  <ItemGroup>
  42.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  43.   </ItemGroup>// 一般进入循环的时候,都会加上这个判断。这个判断逻辑的作用是如开发者在 IDE 里面举行编辑文件的时候,那此文件对应的类型就必要重新处置惩罚,即类型对应的 token 将会被激活。此时在循环跑的逻辑就是浪费的,逻辑必要重跑,因此必要判断 token 是否被取消,减少循环里面的不必要的逻辑损耗  <ItemGroup>
  44.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  45.   </ItemGroup>  <ItemGroup>
  46.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  47.   </ItemGroup>  <ItemGroup>
  48.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  49.   </ItemGroup>// check for cancellation so we don't hang the host  <ItemGroup>
  50.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  51.   </ItemGroup>  <ItemGroup>
  52.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  53.   </ItemGroup>  <ItemGroup>
  54.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  55.   </ItemGroup>token.ThrowIfCancellationRequested();  <ItemGroup>
  56.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  57.   </ItemGroup>  <ItemGroup>
  58.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  59.   </ItemGroup>  <ItemGroup>
  60.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  61.   </ItemGroup> ... // 忽略其他代码  <ItemGroup>
  62.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  63.   </ItemGroup>  <ItemGroup>
  64.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  65.   </ItemGroup>     }  <ItemGroup>
  66.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  67.   </ItemGroup>  <ItemGroup>
  68.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  69.   </ItemGroup> })
复制代码
按照 Roslyn 的计划,在进入大循环等逻辑时,应该多判断一下令牌。这个缘故原由是开发者可能不断在 IDE 里面举行编辑文件,源代码生成器实行过程中对应的文件已经被更改了,本次处置惩罚是无效的,此时对此文件涉及的相关类型的处置惩罚就应该无效掉,等待重新进入。预先多加令牌判断,可以减少无用处置惩罚,减少损耗,避免原本就很卡的 Visual Studio 更加卡顿
在 foreach 里面判断当前的 assemblyClassTypeSymbol 类型是否继承自分部方法要求的返回类型,如以下代码所示
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>    foreach (CollectionExportMethodInfo exportMethodInfo in exportMethodReturnTypeCollectionResultArray)  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>    {  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>token.ThrowIfCancellationRequested();  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>// 判断当前的类型是否是我们必要的类型  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>if (!IsInherit(assemblyClassTypeSymbol, exportMethodInfo.CollectionType))  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>  <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>  <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>{  <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>  <ItemGroup>
  36.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  37.   </ItemGroup>  <ItemGroup>
  38.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  39.   </ItemGroup>    continue;  <ItemGroup>
  40.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  41.   </ItemGroup>  <ItemGroup>
  42.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  43.   </ItemGroup>  <ItemGroup>
  44.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  45.   </ItemGroup>}  <ItemGroup>
  46.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  47.   </ItemGroup>  <ItemGroup>
  48.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  49.   </ItemGroup>  <ItemGroup>
  50.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  51.   </ItemGroup> ... // 忽略其他代码  <ItemGroup>
  52.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  53.   </ItemGroup>  <ItemGroup>
  54.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  55.   </ItemGroup>     }
复制代码
以上的 IsInherit 方法的实现如下
  1.     ///     /// 判断类型继承关系    ///     /// 当前的类型    /// 必要继承的类型    ///     public static bool IsInherit(ITypeSymbol currentType, ITypeSymbol requiredType)    {  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>var baseType = currentType.BaseType;  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>while (baseType is not null)  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>{  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>    if (SymbolEqualityComparer.Default.Equals(baseType, requiredType))  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>    {  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>// 如果基类型是的话  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>return true;  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>    }  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>    // 否则继承找基类型  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>    baseType = baseType.BaseType;  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>}  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>foreach (var currentInheritInterfaceType in currentType.AllInterfaces)  <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>{  <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>    if (SymbolEqualityComparer.Default.Equals(currentInheritInterfaceType, requiredType))  <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>    {  <ItemGroup>
  36.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  37.   </ItemGroup>  <ItemGroup>
  38.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  39.   </ItemGroup>// 如果继承的类型是的话  <ItemGroup>
  40.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  41.   </ItemGroup>  <ItemGroup>
  42.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  43.   </ItemGroup>return true;  <ItemGroup>
  44.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  45.   </ItemGroup>    }  <ItemGroup>
  46.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  47.   </ItemGroup>}  <ItemGroup>
  48.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  49.   </ItemGroup>return false;    }
复制代码
继承条件判断里面是无视引用对象可空情况的,直接使用 SymbolEqualityComparer.Default 判断即可,不用或不该用 SymbolEqualityComparer.IncludeNullability 举行判断。以上的 IsInherit 是一个我常写的工具方法,可以用来判断给定类型是否被继承,包括基类型和接口类型
在真实项目里面,通过 IsInherit 即可过滤大量类型,毕竟能够满足条件的,预期还是少数。再下一步就是寻找构造函数了。在 C# 语法里面,只能做到 new T() 泛型,做不到构造函数里面带参数的情况。源代码生成器里面可以轻易做到这一点,通过这个演练也能让大家看到源代码生成器的威力。在很多通用创建器、工厂模式等,可以打破泛型 T 只能创建无参构造函数的限制,过程中也不用任何反射,都是最直接的代码,对裁剪和 AOT 友好
如果类型满足继承条件,则继承寻找构造函数。感爱好的构造函数的特性是有且只有一个参数,参数类型等于分部方法传入的 context 类型。我这里就完全限定参数类型相称,而不是说其 context 的基类型也可以,这仅仅只是为了简单演示而已
  1. // 判断当前的类型是否是我们必要的类型if (!IsInherit(assemblyClassTypeSymbol, exportMethodInfo.CollectionType)){    continue;}// 遍历其构造函数,找到感爱好的构造函数IMethodSymbol? candidateConstructorMethodSymbol = null;foreach (IMethodSymbol constructorMethodSymbol in ssemblyClassTypeSymbol.Constructors){    if (constructorMethodSymbol.Parameters.Length != 1)    {  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>// 根据需求任务可知,感爱好的构造函数的特性是有且只有一个参数  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>// 如果参数数量不等于 1 则不满足条件  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>continue;    }    // 判断参数的类型是否符合预期    IParameterSymbol parameterSymbol = constructorMethodSymbol.Parameters[0]; // 前面判断限定有且只有一个参数,这里可以放心使用下标访问获取首个参数    var parameterType = parameterSymbol.Type;    // 以下忽略是否可空的判断,因此业务上传入时都是有值的,因此无视可空情况。直接使用 SymbolEqualityComparer.Default 判断即可    if (SymbolEqualityComparer.Default.Equals(parameterType,  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>    exportMethodInfo.ConstructorArgumentType))    {  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>// 如果参数类型满足条件,则这就是感爱好的构造函数  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>candidateConstructorMethodSymbol = constructorMethodSymbol;  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>// 为什么直接 Break 了,不继承找找?继承找找也找不到的,因为不可能存在两个构造函数有相同的参数签名,即不存在两个构造函数的参数数量只有一个且参数类型相同的情况。不信的话,本身写写看就明白了,写任意类型包罗两个构造函数,这两个构造函数的参数数量只有一个且参数类型相同  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>// 固然,如果前面判断条件开放为判断满足 `exportMethodInfo.ConstructorArgumentType` 的基类型条件,那自然这里也许就可能会有多个构造函数的情况,也就必要排优先级了哈。不排也可以,毕竟生成出来的代码都是一样的,但不排的话,语义层面则是不精确的。为了简单演示,这里就直接限制要求类型相同而不是判断继承关系  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>break;    }}
复制代码
能够进入到这一步的,才开始创建列表用于作为返回值
  1.     result ??= new List<ItemGeneratedCodeResult>();
复制代码
判断是否存在满足条件的构造函数,如满足条件,则开始生成代码
  1. result ??= new List();if (candidateConstructorMethodSymbol is not null){    var fullNameDisplayFormat = new SymbolDisplayFormat    (  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>// 带上定名空间和类型名  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>SymbolDisplayGlobalNamespaceStyle.Included,  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>// 定名空间之前加上 global 防止辩论  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>SymbolDisplayTypeQualificationStyle  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>    .NameAndContainingTypesAndNamespaces    );    var className = assemblyClassTypeSymbol.ToDisplayString(fullNameDisplayFormat);    // context => new F1(context)    var generatedCode = $"context => new {className}(context)";    result.Add(new ItemGeneratedCodeResult(generatedCode, exportMethodInfo.GeneratedCodeInfo));}
复制代码
那如果没有存在满足条件的构造函数呢?此时就可以报告一条分析报告信息了
  1. if (candidateConstructorMethodSymbol is not null) {     ... // 忽略其他代码 } else {     // 找不到满足条件的构造函数,给出分析告诫     Diagnostic diagnostic = ...       result.Add(default(ItemGeneratedCodeResult) with     {  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup> Diagnostic = diagnostic,     }); }
复制代码
分析告诫告诫内容也有点知识量,也比力独立,我准备在下文独立和大家介绍,这里就一笔略过。大家在这里只需知道在源代码生成器过程中,如果分析到某些代码难以开展后续的生成工作,可以在此创建分析告诫或错误,用于提示开发者
最后,将 result 列表返回即可
  1. return result?.ToImmutableArray() ?? ImmutableArray<ItemGeneratedCodeResult>.Empty;
复制代码
以上代码将  List 转换为不可变的数组举行返回,如此可以更好的符合分析器的计划。整个寻找整个项目标感爱好的类型和生成部分代码的过程的代码如下
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>IncrementalValuesProvider itemGeneratedCodeResultProvider =  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>    wholeAssemblyClassTypeProvider  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>.Combine(collectionMethodInfoProvider)  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>.Select(static ((INamedTypeSymbol Left, ImmutableArray Right) tuple,  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>    CancellationToken token) =>  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>{  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>    INamedTypeSymbol assemblyClassTypeSymbol = tuple.Left;  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>    var exportMethodReturnTypeCollectionResultArray = tuple.Right;  <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>  <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>    // 慢点创建列表,因为这里是每个类型都会进入一次的,进入次数很多。但大部分类型都不满足条件。因此不提前创建列表能减少很多对象的创建  <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>  <ItemGroup>
  36.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  37.   </ItemGroup>    List? result = null;  <ItemGroup>
  38.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  39.   </ItemGroup>  <ItemGroup>
  40.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  41.   </ItemGroup>    foreach (CollectionExportMethodInfo exportMethodInfo in exportMethodReturnTypeCollectionResultArray)  <ItemGroup>
  42.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  43.   </ItemGroup>  <ItemGroup>
  44.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  45.   </ItemGroup>    {  <ItemGroup>
  46.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  47.   </ItemGroup>  <ItemGroup>
  48.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  49.   </ItemGroup>  <ItemGroup>
  50.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  51.   </ItemGroup>// 一般进入循环的时候,都会加上这个判断。这个判断逻辑的作用是如开发者在 IDE 里面举行编辑文件的时候,那此文件对应的类型就必要重新处置惩罚,即类型对应的 token 将会被激活。此时在循环跑的逻辑就是浪费的,逻辑必要重跑,因此必要判断 token 是否被取消,减少循环里面的不必要的逻辑损耗  <ItemGroup>
  52.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  53.   </ItemGroup>  <ItemGroup>
  54.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  55.   </ItemGroup>  <ItemGroup>
  56.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  57.   </ItemGroup>// check for cancellation so we don't hang the host  <ItemGroup>
  58.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  59.   </ItemGroup>  <ItemGroup>
  60.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  61.   </ItemGroup>  <ItemGroup>
  62.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  63.   </ItemGroup>token.ThrowIfCancellationRequested();  <ItemGroup>
  64.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  65.   </ItemGroup>  <ItemGroup>
  66.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  67.   </ItemGroup>  <ItemGroup>
  68.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  69.   </ItemGroup>// 判断当前的类型是否是我们必要的类型  <ItemGroup>
  70.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  71.   </ItemGroup>  <ItemGroup>
  72.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  73.   </ItemGroup>  <ItemGroup>
  74.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  75.   </ItemGroup>if (!IsInherit(assemblyClassTypeSymbol, exportMethodInfo.CollectionType))  <ItemGroup>
  76.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  77.   </ItemGroup>  <ItemGroup>
  78.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  79.   </ItemGroup>  <ItemGroup>
  80.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  81.   </ItemGroup>{  <ItemGroup>
  82.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  83.   </ItemGroup>  <ItemGroup>
  84.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  85.   </ItemGroup>  <ItemGroup>
  86.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  87.   </ItemGroup>    continue;  <ItemGroup>
  88.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  89.   </ItemGroup>  <ItemGroup>
  90.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  91.   </ItemGroup>  <ItemGroup>
  92.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  93.   </ItemGroup>}  <ItemGroup>
  94.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  95.   </ItemGroup>  <ItemGroup>
  96.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  97.   </ItemGroup>  <ItemGroup>
  98.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  99.   </ItemGroup>// 遍历其构造函数,找到感爱好的构造函数  <ItemGroup>
  100.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  101.   </ItemGroup>  <ItemGroup>
  102.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  103.   </ItemGroup>  <ItemGroup>
  104.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  105.   </ItemGroup>IMethodSymbol? candidateConstructorMethodSymbol = null;  <ItemGroup>
  106.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  107.   </ItemGroup>  <ItemGroup>
  108.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  109.   </ItemGroup>  <ItemGroup>
  110.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  111.   </ItemGroup>foreach (IMethodSymbol constructorMethodSymbol in assemblyClassTypeSymbol.Constructors)  <ItemGroup>
  112.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  113.   </ItemGroup>  <ItemGroup>
  114.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  115.   </ItemGroup>  <ItemGroup>
  116.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  117.   </ItemGroup>{  <ItemGroup>
  118.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  119.   </ItemGroup>  <ItemGroup>
  120.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  121.   </ItemGroup>  <ItemGroup>
  122.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  123.   </ItemGroup>    if (constructorMethodSymbol.Parameters.Length != 1)  <ItemGroup>
  124.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  125.   </ItemGroup>  <ItemGroup>
  126.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  127.   </ItemGroup>  <ItemGroup>
  128.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  129.   </ItemGroup>    {  <ItemGroup>
  130.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  131.   </ItemGroup>  <ItemGroup>
  132.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  133.   </ItemGroup>  <ItemGroup>
  134.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  135.   </ItemGroup>  <ItemGroup>
  136.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  137.   </ItemGroup>continue;  <ItemGroup>
  138.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  139.   </ItemGroup>  <ItemGroup>
  140.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  141.   </ItemGroup>  <ItemGroup>
  142.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  143.   </ItemGroup>    }  <ItemGroup>
  144.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  145.   </ItemGroup>  <ItemGroup>
  146.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  147.   </ItemGroup>  <ItemGroup>
  148.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  149.   </ItemGroup>    // 判断参数的类型是否符合预期  <ItemGroup>
  150.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  151.   </ItemGroup>  <ItemGroup>
  152.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  153.   </ItemGroup>  <ItemGroup>
  154.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  155.   </ItemGroup>    IParameterSymbol parameterSymbol = constructorMethodSymbol.Parameters[0];  <ItemGroup>
  156.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  157.   </ItemGroup>  <ItemGroup>
  158.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  159.   </ItemGroup>  <ItemGroup>
  160.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  161.   </ItemGroup>    var parameterType = parameterSymbol.Type;  <ItemGroup>
  162.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  163.   </ItemGroup>  <ItemGroup>
  164.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  165.   </ItemGroup>  <ItemGroup>
  166.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  167.   </ItemGroup>    if (SymbolEqualityComparer.Default.Equals(parameterType,  <ItemGroup>
  168.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  169.   </ItemGroup>  <ItemGroup>
  170.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  171.   </ItemGroup>  <ItemGroup>
  172.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  173.   </ItemGroup>  <ItemGroup>
  174.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  175.   </ItemGroup>    exportMethodInfo.ConstructorArgumentType))  <ItemGroup>
  176.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  177.   </ItemGroup>  <ItemGroup>
  178.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  179.   </ItemGroup>  <ItemGroup>
  180.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  181.   </ItemGroup>    {  <ItemGroup>
  182.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  183.   </ItemGroup>  <ItemGroup>
  184.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  185.   </ItemGroup>  <ItemGroup>
  186.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  187.   </ItemGroup>  <ItemGroup>
  188.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  189.   </ItemGroup>candidateConstructorMethodSymbol = constructorMethodSymbol;  <ItemGroup>
  190.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  191.   </ItemGroup>  <ItemGroup>
  192.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  193.   </ItemGroup>  <ItemGroup>
  194.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  195.   </ItemGroup>  <ItemGroup>
  196.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  197.   </ItemGroup>break;  <ItemGroup>
  198.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  199.   </ItemGroup>  <ItemGroup>
  200.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  201.   </ItemGroup>  <ItemGroup>
  202.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  203.   </ItemGroup>    }  <ItemGroup>
  204.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  205.   </ItemGroup>  <ItemGroup>
  206.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  207.   </ItemGroup>  <ItemGroup>
  208.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  209.   </ItemGroup>}  <ItemGroup>
  210.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  211.   </ItemGroup>  <ItemGroup>
  212.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  213.   </ItemGroup>  <ItemGroup>
  214.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  215.   </ItemGroup>result ??= new List();  <ItemGroup>
  216.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  217.   </ItemGroup>  <ItemGroup>
  218.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  219.   </ItemGroup>  <ItemGroup>
  220.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  221.   </ItemGroup>var fullNameDisplayFormat = new SymbolDisplayFormat  <ItemGroup>
  222.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  223.   </ItemGroup>  <ItemGroup>
  224.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  225.   </ItemGroup>  <ItemGroup>
  226.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  227.   </ItemGroup>(  <ItemGroup>
  228.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  229.   </ItemGroup>  <ItemGroup>
  230.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  231.   </ItemGroup>  <ItemGroup>
  232.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  233.   </ItemGroup>    // 带上定名空间和类型名  <ItemGroup>
  234.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  235.   </ItemGroup>  <ItemGroup>
  236.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  237.   </ItemGroup>  <ItemGroup>
  238.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  239.   </ItemGroup>    SymbolDisplayGlobalNamespaceStyle.Included,  <ItemGroup>
  240.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  241.   </ItemGroup>  <ItemGroup>
  242.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  243.   </ItemGroup>  <ItemGroup>
  244.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  245.   </ItemGroup>    // 定名空间之前加上 global 防止辩论  <ItemGroup>
  246.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  247.   </ItemGroup>  <ItemGroup>
  248.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  249.   </ItemGroup>  <ItemGroup>
  250.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  251.   </ItemGroup>    SymbolDisplayTypeQualificationStyle  <ItemGroup>
  252.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  253.   </ItemGroup>  <ItemGroup>
  254.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  255.   </ItemGroup>  <ItemGroup>
  256.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  257.   </ItemGroup>  <ItemGroup>
  258.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  259.   </ItemGroup>.NameAndContainingTypesAndNamespaces  <ItemGroup>
  260.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  261.   </ItemGroup>  <ItemGroup>
  262.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  263.   </ItemGroup>  <ItemGroup>
  264.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  265.   </ItemGroup>);  <ItemGroup>
  266.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  267.   </ItemGroup>  <ItemGroup>
  268.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  269.   </ItemGroup>  <ItemGroup>
  270.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  271.   </ItemGroup>var className = assemblyClassTypeSymbol.ToDisplayString(fullNameDisplayFormat);  <ItemGroup>
  272.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  273.   </ItemGroup>  <ItemGroup>
  274.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  275.   </ItemGroup>  <ItemGroup>
  276.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  277.   </ItemGroup>if (candidateConstructorMethodSymbol is not null)  <ItemGroup>
  278.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  279.   </ItemGroup>  <ItemGroup>
  280.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  281.   </ItemGroup>  <ItemGroup>
  282.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  283.   </ItemGroup>{  <ItemGroup>
  284.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  285.   </ItemGroup>  <ItemGroup>
  286.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  287.   </ItemGroup>  <ItemGroup>
  288.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  289.   </ItemGroup>    // context => new F1(context)  <ItemGroup>
  290.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  291.   </ItemGroup>  <ItemGroup>
  292.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  293.   </ItemGroup>  <ItemGroup>
  294.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  295.   </ItemGroup>    var generatedCode = $"context => new {className}(context)";  <ItemGroup>
  296.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  297.   </ItemGroup>  <ItemGroup>
  298.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  299.   </ItemGroup>  <ItemGroup>
  300.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  301.   </ItemGroup>    result.Add(new ItemGeneratedCodeResult(generatedCode, exportMethodInfo.GeneratedCodeInfo));  <ItemGroup>
  302.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  303.   </ItemGroup>  <ItemGroup>
  304.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  305.   </ItemGroup>  <ItemGroup>
  306.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  307.   </ItemGroup>}  <ItemGroup>
  308.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  309.   </ItemGroup>  <ItemGroup>
  310.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  311.   </ItemGroup>  <ItemGroup>
  312.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  313.   </ItemGroup>else  <ItemGroup>
  314.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  315.   </ItemGroup>  <ItemGroup>
  316.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  317.   </ItemGroup>  <ItemGroup>
  318.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  319.   </ItemGroup>{  <ItemGroup>
  320.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  321.   </ItemGroup>  <ItemGroup>
  322.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  323.   </ItemGroup>  <ItemGroup>
  324.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  325.   </ItemGroup>    // 找不到满足条件的构造函数,给出分析告诫  <ItemGroup>
  326.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  327.   </ItemGroup>  <ItemGroup>
  328.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  329.   </ItemGroup>  <ItemGroup>
  330.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  331.   </ItemGroup>    Diagnostic diagnostic = ...  <ItemGroup>
  332.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  333.   </ItemGroup>  <ItemGroup>
  334.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  335.   </ItemGroup>  <ItemGroup>
  336.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  337.   </ItemGroup>      result.Add(default(ItemGeneratedCodeResult) with  <ItemGroup>
  338.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  339.   </ItemGroup>  <ItemGroup>
  340.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  341.   </ItemGroup>  <ItemGroup>
  342.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  343.   </ItemGroup>    {  <ItemGroup>
  344.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  345.   </ItemGroup>  <ItemGroup>
  346.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  347.   </ItemGroup>  <ItemGroup>
  348.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  349.   </ItemGroup>  <ItemGroup>
  350.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  351.   </ItemGroup>Diagnostic = diagnostic,  <ItemGroup>
  352.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  353.   </ItemGroup>  <ItemGroup>
  354.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  355.   </ItemGroup>  <ItemGroup>
  356.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  357.   </ItemGroup>    });  <ItemGroup>
  358.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  359.   </ItemGroup>  <ItemGroup>
  360.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  361.   </ItemGroup>  <ItemGroup>
  362.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  363.   </ItemGroup>}  <ItemGroup>
  364.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  365.   </ItemGroup>  <ItemGroup>
  366.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  367.   </ItemGroup>    }  <ItemGroup>
  368.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  369.   </ItemGroup>  <ItemGroup>
  370.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  371.   </ItemGroup>    return result?.ToImmutableArray() ?? ImmutableArray<ItemGeneratedCodeResult>.Empty;  <ItemGroup>
  372.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  373.   </ItemGroup>  <ItemGroup>
  374.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  375.   </ItemGroup>});
复制代码
为了能够在后续步调更好地聚焦处置惩罚,这里也同样在 itemGeneratedCodeResultProvider 叠加一个 Where 举行过滤,去掉空集,代码如下
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>IncrementalValuesProvider itemGeneratedCodeResultProvider =  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>    wholeAssemblyClassTypeProvider  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>.Combine(collectionMethodInfoProvider)  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>.Select(static ((INamedTypeSymbol Left, ImmutableArray Right) tuple,  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>    CancellationToken token) =>  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>{  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>    ... // 忽略其他代码  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>})  <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>  <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>.Where(t => t != ImmutableArray.Empty);
复制代码
如此即可确保后续步调拿到的 itemGeneratedCodeResultProvider 提供的值都不会是空集
在这里,大家看到了很多熟悉的类似 Linq 里面的 Where 和 Select 方法。这些方法只是定名上和 Linq 相同,实际上不是原来的 Linq 的方法。但从方法的用途上和计划上,可以看到在 IIncrementalGenerator 这部分计划里面是非常靠近 Linq 的计划的。在更底层的计划上,所盼望的就是让数据可以和 Linq 的数据流计划一样,能够一级级传递,且过程中是 Lazy 的和带缓存的。焦点目标就是减少计算压力,充实使用 Roslyn 的不可变性带来的缓存机制,减少分析过程的计算压力,不让原本就很卡的 Visual Studio 更加卡。我将在下文基础知识部分和大家详细剖析 Where 和 Select 和 Combine 等这几个基础 IIncrementalGenerator 增量源代码生成器的专有方法
通过以上的步调,就完成了收集各个感爱好类型的构造函数的过程,且生成了对应的创建器委托代码。接下来就可以举行组装最终的代码了
以上是逐个类型跑出来的,必要将其组装起来,生成最终的代码。这里采用的方法是先用 Collect 将其聚合为一个大数组,再使用 SelectMany 将其散开。为什么必要做合分的处置惩罚?缘故原由是 itemGeneratedCodeResultProvider 提供的数组是一个类型对应在多个分部方法里面的生成代码,而最终必要生成的是单个分部方法包罗多个类型的代码,且盼望各个分部方法独立生成。于是就必要先调用 Collect 将其聚合为一个大数组,如此才能让各个分部方法拿到所有感爱好的类型的生成代码,再调用 SelectMany 方法让每个分部方法独立输出,代码如下
  1. itemGeneratedCodeResultProvider
  2. .Collect()
  3. .SelectMany((ImmutableArray<ImmutableArray<ItemGeneratedCodeResult>> array, CancellationToken oken) =>
  4. {
  5.      ... // 忽略其他代码
  6. });
复制代码
原本 itemGeneratedCodeResultProvider 就是一个多值提供器,提供的每个值都是 ImmutableArray 类型。调用 Collect 之后,就转换成了 ImmutableArray 类型,套了两层数组。在 SelectMany 里面,必要先将其拆散,按照 ItemGeneratedCodeResult 里面的 ExportMethodGeneratedCodeInfo 举行分组。这时候采用 Linq 来写就非常简单,代码如下
  1. itemGeneratedCodeResultProvider .Collect() .SelectMany((ImmutableArray array, CancellationTokentoken) => {     IEnumerable group = array  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup> .SelectMany(t => t)  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup> // 如果 Diagnostic 不是空,则证实这条是用来报告的,忽略  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup> .Where(t => t.Diagnostic is null)  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup> .GroupBy(t => t.ExportMethodGeneratedCodeInfo);     ... // 忽略其他代码 });
复制代码
这里拿到的 IEnumerable group 看似很长,实在寄义非常明白,表示的是多个组。每个组的领导就是 GeneratedCodeInfo 类型,实际寄义是分部方法。简单来说可以当作 IEnumerable 类型,细分 分部方法组 就包罗了分部方法的信息本身,以及各个满足条件的类型和其生成代码。每个 分部方法组 就可以构成一个最终生成代码
将 IEnumerable group 举行遍历,每一项都可生成一个独立的分部方法的实现代码
  1.   IEnumerable<IGrouping<GeneratedCodeInfo, ItemGeneratedCodeResult>> group = array
  2.       .SelectMany(t => t)
  3.       // 这条是用来报告的,忽略
  4.       .Where(t => t.Diagnostic is null)
  5.       .GroupBy(t => t.ExportMethodGeneratedCodeInfo);
  6.   var generatedCodeList = new List<GeneratedCodeInfo>();
  7.   foreach (IGrouping<GeneratedCodeInfo, ItemGeneratedCodeResult> temp in group)
  8.   {
  9.       // 在这里就是可以组装出各个标记了 CollectionAttribute 特性的分部方法的实现代码
  10.       ... // 忽略其他代码
  11.   }
复制代码
以下就是组装标志了 CollectionAttribute 特性的分部方法的实现代码,先将各个满足条件的类型的生成代码放入到 StringBuilder 里面,转换为方法体焦点内容,代码如下
  1. var generatedCodeList = new List();foreach (IGrouping temp in group){    // 举行组装生成代码。在 Select 系列方法组装会比在 RegisterSourceOutput 更好,在这里更加便被打断    var stringBuilder = new StringBuilder();    foreach (ItemGeneratedCodeResult itemGeneratedCodeResult in temp)    {  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>token.ThrowIfCancellationRequested();  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>//  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup> yield return context => new F1(context);  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>stringBuilder.AppendLine($"  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup> yield return itemGeneratedCodeResult.ItemGeneratedCode};");    }    // 严谨一些,添加 break 语句。顺带办理收集不到任何一个类型的情况    stringBuilder.AppendLine("  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup> yield break;");}
复制代码
在以上生成代码里面,还在最后添加了  yield break; 代码,如此可以顺带办理收集不到任何一个类型的情况,即使收集不到一个类型,也能返回空集,而不会让构建炸掉
再根据上文提供的 yield return context => new F1(context); 用于被替换的预置内容,将其举行替换,即可完成分部方法实现方法体的内容
  1. // 这是用来替换的代码var replacedCode = "  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>yield return context => new F1(context);";GeneratedCodeInfo generatedCodeInfo = temp.Key;var generatedCode = generatedCodeInfo.GeneratedCode.Replace(replacedCode, stringBuilder.ToString());
复制代码
当前的 generatedCode 变量的内容大概如下,即以下代码内容就是最终的分部方法生成的方法体内容示例
  1. namespace KawhawnahemCanalllearlerwhu;public static partial class FooCollection{    public static partial global::System.Collections.Generic.IEnumerableGetFooCreatorList()    {  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup> yield return context => new global::KawhawnahemCanalllearlerwhu.F1(context);  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup> yield return context => new global::KawhawnahemCanalllearlerwhu.F2(context);  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup> yield break;    }}
复制代码
生成最终代码之后,将其加入到 generatedCodeList 列表里面,如以下代码所示
  1. generatedCodeList.Add(new GeneratedCodeInfo(generatedCode, generatedCodeInfo.Name));
复制代码
最后,将 generatedCodeList 列表返回即可
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>IncrementalValuesProvider generatedCodeInfoProvider = itemGeneratedCodeResultProvider  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>    .Collect()  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>    .SelectMany((ImmutableArray array, CancellationToken token) =>  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>    {  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>IEnumerable group = array  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>    .SelectMany(t => t)  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>    // 这条是用来报告的,忽略  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>    .Where(t => t.Diagnostic is null)  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>    .GroupBy(t => t.ExportMethodGeneratedCodeInfo);  <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>  <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>var generatedCodeList = new List();  <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>  <ItemGroup>
  36.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  37.   </ItemGroup>foreach (IGrouping temp in group)  <ItemGroup>
  38.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  39.   </ItemGroup>  <ItemGroup>
  40.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  41.   </ItemGroup>{  <ItemGroup>
  42.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  43.   </ItemGroup>  <ItemGroup>
  44.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  45.   </ItemGroup>    var generatedCode = ... // 最终生成的分部方法的方法体  <ItemGroup>
  46.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  47.   </ItemGroup>  <ItemGroup>
  48.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  49.   </ItemGroup>    generatedCodeList.Add(new GeneratedCodeInfo(generatedCode, generatedCodeInfo.Name));  <ItemGroup>
  50.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  51.   </ItemGroup>  <ItemGroup>
  52.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  53.   </ItemGroup>}  <ItemGroup>
  54.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  55.   </ItemGroup>  <ItemGroup>
  56.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  57.   </ItemGroup>return generatedCodeList;  <ItemGroup>
  58.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  59.   </ItemGroup>    });
复制代码
是否大家好奇为什么 generatedCodeInfoProvider 是 IncrementalValuesProvider 类型?明显最后返回的是 List generatedCodeList 列表?这是因为当前调用的就是 SelectMany 方法,其功能和 Linq 的 SelectMany 方法一样,都是将返回的列表举行拆散
最后一步就是将生成的代码举行注入,这里调用的是 RegisterImplementationSourceOutput 方法。回顾一下几个注入生成代码的方法的差别,其中 RegisterImplementationSourceOutput 的作用是注册具体的实现部分的生成代码。这个方法的调用可以让 IDE 举行充实的优化,因为具体的实现的内容不影响外部的语法语义分析,外部的语法语义分析靠界说部分即可完成,因此对于实现的内容部分可以尽量慢点调用和减少调用频次。刚幸亏本演练里面,生成的代码就是具体的实现部分,调用 RegisterImplementationSourceOutput 方法是非常合适的
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>context.RegisterImplementationSourceOutput(generatedCodeInfoProvider,  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>    (SourceProductionContext productionContext, GeneratedCodeInfo generatedCodeInfo) =>  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>    {  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>productionContext.AddSource($"{generatedCodeInfo.Name}.cs", generatedCodeInfo.GeneratedCode);  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>    });
复制代码
按照源代码生成器的最佳实践来说,在 RegisterImplementationSourceOutput 等注册代码步调里面,应该接近没有逻辑。即在值提供器步调时,就将代码生成完成,到 RegisterXxx 方法里面只做注册而已。这样就比力方便在前面步调举行打断,以及缓存复用
报告 Diagnostic 信息

认真阅读文章的伙伴也许还记得上文部分提到了 Diagnostic 信息。在源代码生成器的过程中,如果发现某些代码不符合预期,可以通过报告 Diagnostic 信息,用于提示开发者。在上文的代码里面,如果找不到满足条件的构造函数,就会报告一条分析告诫。这里就来详细介绍如何报告 Diagnostic 信息
回到 itemGeneratedCodeResultProvider 变量的赋值部分代码,即使对全项目标类型 wholeAssemblyClassTypeProvider 举行“遍历”的时候,如果一个类型满足分部方法收集条件,但不存在任何一个满足条件的构造函数时,应该给出分析告诫。如本演练给出的 F3 测试类型的界说如下
  1. public class F3 : IFoo{    public F3()    {  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>// 忽略其他代码    }}
复制代码
对应的分部方法的界说如下
  1. public static partial class FooCollection
  2. {
  3.     [Collection]
  4.     public static partial IEnumerable<Func<IContext, IFoo>> GetFooCreatorList();
  5. }
复制代码
可以明显看出给出的 F3 测试类型是歪楼的,没有构造函数满足 GetFooCreatorList 收集条件。于是在 wholeAssemblyClassTypeProvider 举行遍历的过程中,应该对这些歪楼的类型给出告诫
  1. IncrementalValuesProvider wholeAssemblyClassTypeProvider = ...wholeAssemblyClassTypeProvider    .Combine(collectionMethodInfoProvider)    .Select(static ((INamedTypeSymbol Left, ImmutableArray Right) tuple,  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>CancellationToken token) =>    {  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>INamedTypeSymbol assemblyClassTypeSymbol = tuple.Left;  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>var exportMethodReturnTypeCollectionResultArray = tuple.Right;  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>List? result = null;  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>foreach (CollectionExportMethodInfo exportMethodInfo inexportMethodReturnTypeCollectionResultArray)  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>{  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>    ... // 忽略其他代码  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>    // 遍历其构造函数,找到感爱好的构造函数  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>    IMethodSymbol? candidateConstructorMethodSymbol = null;  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>    ... // 尝试获取满足条件的构造函数  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>    if (candidateConstructorMethodSymbol is not null)  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>    {  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>  <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>    }  <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>    else  <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>    {  <ItemGroup>
  36.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  37.   </ItemGroup>  <ItemGroup>
  38.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  39.   </ItemGroup>Diagnostic diagnostic = ...  <ItemGroup>
  40.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  41.   </ItemGroup>  <ItemGroup>
  42.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  43.   </ItemGroup>result.Add(default(ItemGeneratedCodeResult) with  <ItemGroup>
  44.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  45.   </ItemGroup>  <ItemGroup>
  46.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  47.   </ItemGroup>{  <ItemGroup>
  48.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  49.   </ItemGroup>  <ItemGroup>
  50.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  51.   </ItemGroup>    Diagnostic = diagnostic,  <ItemGroup>
  52.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  53.   </ItemGroup>  <ItemGroup>
  54.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  55.   </ItemGroup>});  <ItemGroup>
  56.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  57.   </ItemGroup>    }  <ItemGroup>
  58.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  59.   </ItemGroup>}  <ItemGroup>
  60.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  61.   </ItemGroup>return result?.ToImmutableArray() ?? ImmutableArray<ItemGeneratedCodeResult>.Empty;    })
复制代码
现在咱来开始填补 Diagnostic diagnostic = ... 这句代码的具体内容。起首必要创建一个 DiagnosticDescriptor 对象,用于描述这个 Diagnostic 信息的基本信息,如 ID、Title、MessageFormat、Category 等。这是因为大部分的 Diagnostic 基本信息都是固定的,唯一不同的就是具体的 Message 提示消息内容的一些参数不同,以及代码 Location 的不同而已。再加上为了让分析器能够提供给全球的开发者使用,自然要照顾多语言问题,这部分就可以独立出来界说,不用每次报告都重复生成。固然了,为了演示方便,我这里就在每次循环里面,每找到一次不满足条件的构造函数就创建一个 DiagnosticDescriptor 对象,实际项目中应该是提前界说好的,不用每次循环都创建,甚至作为静态的字段都是公道的
  1. // 找不到满足条件的构造函数,给出分析警告
  2. var diagnosticDescriptor = new DiagnosticDescriptor
  3. (
  4.     id: nameof(Resources.Kaw001),
  5.     title: Localize(nameof(Resources.Kaw001)),
  6.     messageFormat: Localize(nameof(Resources.Kaw001_Message)),
  7.     category: "FooCompiler",
  8.     DiagnosticSeverity.Warning,
  9.     isEnabledByDefault: true
  10. );
复制代码
大家可以发现,以上代码写了 Resources.Kaw001 资源界说,这部分是依靠在分析器项目里面创建 Resources.resx 资源而被生成的属性。通过创建 Resources.resx 文件,可以复用原本 dotnet 内建的多语言机制,生成多语言程序集等方式提供多语言包。本文这里不过多介绍多语言的创建方式,大家感爱好还请自行了解
具体做法就是创建 Resources.resx 文件,确保在 csproj 项目里面里面设置为 ResXFileCodeGenerator 生成方式或其他的生成方式
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>    True      True      Resources.resx  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>  ResXFileCodeGenerator      Resources.Designer.cs      
复制代码

在 Resources.resx 文件里面添加两项,内容分别如下

  • Kaw001 : 找不到符合预期的构造函数
  • Kaw001_Message : 无法从 {0} 类型中找到构造函数,盼望构造函数的只有一个参数,且参数为 {1} 类型

如上文代码,可见 Kaw001 将被当成标题,而 Kaw001_Message 被作为具体告诫内容。其中 Kaw001_Message 添加了 {0} 和 {1} 内容,用于分别替换为具体告诫信息内容的具体类型
为了作为告诫内容,在 DiagnosticDescriptor 必要将 DiagnosticSeverity 设置为 Warning 品级。如盼望作为错误,则必要设置为 Error 才可以。可用选项如下所示
  1.   /// <summary>Describes how severe a diagnostic is.</summary>
  2.   public enum DiagnosticSeverity
  3.   {
  4.     /// <summary>
  5.     /// Something that is an issue, as determined by some authority,
  6.     /// but is not surfaced through normal means.
  7.     /// There may be different mechanisms that act on these issues.
  8.     /// </summary>
  9.     Hidden,
  10.     /// <summary>
  11.     /// Information that does not indicate a problem (i.e. not prescriptive).
  12.     /// </summary>
  13.     Info,
  14.     /// <summary>Something suspicious but allowed.</summary>
  15.     Warning,
  16.     /// <summary>
  17.     /// Something not allowed by the rules of the language or other authority.
  18.     /// </summary>
  19.     Error,
  20.   }
复制代码
以上 category 分类是本身分析器内自界说的,这部分没有做要求,只要本身分类好就可以了。在我所在的团队的 https://github.com/dotnet-campus/dotnetCampus.MSBuildUtils 开源项目里面就内建了一些常用的分类,大家如果没有思路可以参考
上文代码中的 DiagnosticDescriptor 构造函数参数的 Localize 方法的实现如下,其作用是返回支持语言文化的 LocalizableString 类型而不是具体字符串
  1.     public static LocalizableString Localize(string key) =>  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>new LocalizableResourceString(key, Resources.ResourceManager, typeof(Resources));
复制代码
上文代码里面选用的 Kaw001 也是有约束的,即这是一个 C# 的标识符,使用前缀加数字形式,长度小于 15 个字符,确保唯一性。详细约束请参阅 https://learn.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/choosing-diagnostic-ids
完成了对 DiagnosticDescriptor 的界说之后,接下来就可以开始创建 Diagnostic 对象。也如 DiagnosticDescriptor 的构造函数可以看到,实在基本信息都全了,剩下的就是填充具体告诫信息的参数内容,即 {0} 和 {1} 参数内容,以及可选的告诫的代码 Location 在哪信息而已
  1. var fullNameDisplayFormat = new SymbolDisplayFormat(    // 带上定名空间和类型名    SymbolDisplayGlobalNamespaceStyle.Included,    // 定名空间之前加上 global 防止辩论    SymbolDisplayTypeQualificationStyle  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>.NameAndContainingTypesAndNamespaces);var className = assemblyClassTypeSymbol.ToDisplayString(fullNameDisplayFormat);// 无法从 {0} 类型中找到构造函数,盼望构造函数的只有一个参数,且参数类型为 {1}Diagnostic diagnostic = Diagnostic.Create(diagnosticDescriptor, exportMethodInfo.Location,    messageArgs:    [  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>className,  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>exportMethodInfo.ConstructorArgumentType.ToDisplayString(fullNameDisplayFormat)    ]);
复制代码
如以上代码,可见告诫飘红就在分部方法的界说上,内容就是当前的类型和分部方法构成的告诫信息。按照本演练的例子,输出信息大概如下
  1. C:\lindexi\Code\Roslyn\KawhawnahemCanalllearlerwhu\KawhawnahemCanalllearlerwhu\Foo.cs(40,5,41,81): warning Kaw001: 无法从 global::KawhawnahemCanalllearlerwhu.F3 类型中找到构造函数,期望构造函数的只有一个参数,且参数为 global::KawhawnahemCanalllearlerwhu.IContext 类型
复制代码

这个过程中可以看到似乎有分析器的影子在里面了,报告 Diagnostic 过程本身也就是分析器的一个部分,大部分分析器的功能都是和源代码生成器相互重叠的,比如都必要举行语法语义的分析。不同点只是源代码生成器多了一个生成代码的过程
不过这里演示的还不是专用分析器的功能,在下文将会告诉大家如何写一个专用分析器。专用的分析器有更多好用的方法,其焦点在于分析要尽量不影响用户编写代码,有各个时机可以选。但源代码生成器是如果没有生成,可能就影响到了用户写代码了,可选时机少了很多
以上就是本演练的全部实现内容。盼望能够让大家了解到一个比力全面的源代码生成器的各个方面内容。大家也不要被此吓到,这是我专门找到的能够覆盖源代码生成器所用大部分技术的例子。大部分源代码生成器都不会用到涉及这么全面的技术内容的。以上的例子是我按照我所在的团队的可产品化的开源项目简化的内容,更多细节和产品化处置惩罚逻辑,可以去参考开源项目
使用了本演练介绍的技术的可产品化使用的开源项目: https://github.com/dotnet-campus/Telescope
代码

本章的代码放在 githubgitee 上,可以使用如下命令行拉取代码。我整个代码堆栈比力庞大,使用以下命令行可以举行部分拉取,拉取速率比力快
先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
  1. git init
  2. git remote add origin https://gitee.com/lindexi/lindexi_gd.git
  3. git pull origin 7799af7403b6408b1e30151e144b2273c86433c7
复制代码
以上使用的是国内的 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继承输入以下代码,将 gitee 源换成 github 源举行拉取代码。如果依然拉取不到代码,可以发邮件向我要代码
  1. git remote remove origin
  2. git remote add origin https://github.com/lindexi/lindexi_gd.git
  3. git pull origin 7799af7403b6408b1e30151e144b2273c86433c7
复制代码
获取代码之后,进入 Roslyn/KawhawnahemCanalllearlerwhu 文件夹,即可获取到源代码
生成的源代码保存到当地文件

在本演练里面生成的代码还算简单,也不知道大家是否在一开始就在好奇生成的代码是什么样子的。接下来我将告诉大家如何将生成的源代码保存到当地文件
对于比力复杂的生成代码而言,有时候会导致项目构建不通过。这个技术在实际开发中非常有用,默认的生成代码只能在 VisualStudio 里面的分析器里面一项项展开查看,没有具体的文件路径,对于源代码生成器作者的调试分析不够友好,也不方便将生成的代码发送给其他开发者辅助调试。将生成的源代码保存到当地文件,可以更好的辅助大家举行阅读和调试,以及采用第三方工具辅助分析生成的代码内容
将生成的源代码保存到当地文件只需在 csproj 项目文件里面设置 EmitCompilerGeneratedFiles 属性即可,设置完成之后,默认的生成源代码将会存放到 $(IntermediateOutputPath)\generated 文件夹里面,这里的 $(IntermediateOutputPath) 由 obj\$(Configuration)\$(TargetFramework.ToLowerInvariant())\ 构成,调试下的输出大概是 obj\Debug\net9.0\ 等类似的文件夹里
  1.   <PropertyGroup>
  2.     <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
  3.   </PropertyGroup>
复制代码
如果盼望本身指定保存的文件夹,可以自行设置 EmitCompilerGeneratedFiles 属性,如以下代码
  1.   <PropertyGroup>
  2.     <CompilerGeneratedFilesOutputPath>Generated\$(TargetFramework)</CompilerGeneratedFilesOutputPath>
  3.   </PropertyGroup>
复制代码
以上代码之所以拼接上 TargetFramework 是因为盼望默认处置惩罚多框架的文件辩论问题,源代码生成器会在多框架下分别实行,为每个框架生成独立的代码。如果在多框架项目下没有配置加上 TargetFramework 将会造成生成的源代码存放的文件辩论
更多请参阅 将 Source Generator 生成的源代码保存到当地文件
基础知识

在上文介绍了基础 IIncrementalGenerator 增量源代码生成器的专有方法,如 Where 和 Select 和 Combine 等,这里将详细介绍这几个方法的用法和计划
开始之前重新介绍两个类型的值提供器,分别是 IncrementalValuesProvider 多值提供器和 IncrementalValueProvider 单值提供器。这两个类型的值提供器是源代码生成器的焦点,用于提供源代码生成器的输入源
对于 IncrementalValuesProvider 多值提供器来说,里面的每一项都是独立的。比如以下代码
  1. IncrementalValuesProvider<Foo> provider = ...
  2. var t = provider.Select(...);
复制代码
当某个 Foo 项变更的时候,那么 Select 方法里面的代码就会重新实行,且只实行一次。其他没有变更的 Foo 项则不会触发 Select 方法里面的委托实行。通过类似的方式可以应用缓存,减少计算工作量
有些伙伴会感谢增量源代码生成器这部分 API 比力复杂。确实是比力复杂。但大家必要明白的是,咱现在正在编写的是和编译器相关的代码,所有和编译器沾边的,其难度都不低。在 Roslyn 以及其周边的设施的计划上,都寻求性能、编写的复杂度、可维护性等多方面的均衡。如果没有源代码生成的 API 封装,直接面临最裸的编译器相关实现逻辑,那其开发难度和入门门槛可想而知的高
在性能寻求方面上,性能优化常用套路里面就是减少计算量。除了语言层面能够提升之外,减少计算工作量能达到算法级的优化,这才是真正的优化。尽管 Roslyn 在发布之初就强调了性能,但即使单次构建足够快,架不住次数多。比如一个代码文件压到 1 毫秒,但我的项目有 2000 个文件,我假设无时不刻都在修改代码,那么每次构建就是 2000 毫秒,也就是 2 秒。这个时间对于一个大型项目来说,还是比力可观的。但事实上,绝大部分的代码我都没有动到,只有少部分的代码在修改。这时候就必要增量构建,只处置惩罚修改的代码,这样就能大大减少构建时间。这就是增量构建的优势所在
为了告竣增量构建,就必要引入缓存不可变机制。引入缓存不可变机制,在一定程度上能够降低整体逻辑复杂度,不必要让程序猿去内耗对象是否被变更等问题。也方便底层设施搭建者举行复现问题,即方便重现问题,各个部件都是不可变的,方法都是无副作用的,自然重现步调就简单了
在多方均衡之下,就有了现在大家所看到的 IIncrementalGenerator 增量源代码生成器的各个方法了。虽然看起来复杂,但只要想想原本的开发难度和复杂度,能够被降低到这个程度,就不会觉得这个 API 复杂了
对于 IncrementalValueProvider 单值提供器来说,里面只提供一个值,有时候这个值是一个数组集合,有时候里面就真的是一个值,比如下文会和大家介绍到的配置内容。在 IIncrementalGenerator 增量源代码生成器里面就充满了聚合和散开的逻辑,也推荐这么干,这样的逻辑更底层的思想是实现细颗粒度管控,能够更好地使用缓存,减少计算工作量
无论是 IncrementalValuesProvider 多值提供器还是 IncrementalValueProvider 单值提供器,整体计划都是采用管线方式,走数据流的方式,让数据一步步往下走。在每一步的输出里面都举行缓存检查,如果命中缓存,即没有更改,则不会触发后续的计算。这也就是 IIncrementalGenerator 增量源代码生成器定名的由来,即增量构建,只处置惩罚变更的部分。而 Linq 刚好就是数据流的一个现有实践,在增量源代码生成器里面复用了这部分的计划思想,只是 API 实现和行为略微不同,接下来我将逐一和大家介绍这几个方法的用法和计划
本章以下的介绍顺序保持和 https://github.com/dotnet/roslyn/blob/main/docs/features/incremental-generators.md 官方文档相同的顺序,对应的代码附图来源于此官方文档
Select

方法签名:
  1. public static partial class IncrementalValueSourceExtensions
  2. {
  3.     // 1 => 1 transform
  4.     // 1 对 1 的转换,从 TSource 转换为 TResult 类型的输出
  5.     // 为了简单表述,我使用 `IncrementalValue[s]Provider` 代表 `IncrementalValuesProvider` 和 `IncrementalValueProvider` 两个类型的值提供器都适用的情况
  6.     public static IncrementalValue[s]Provider<TResult> Select<TSource, TResult>(this IncrementalValue[s]Provider<TSource> source, Func<TSource, CancellationToken, TResult> selector);
  7. }
复制代码
这是一个最常用的转换逻辑,用于从当前提供的数据转换为新的数据举行输出,可同时在 IncrementalValuesProvider 多值提供器和 IncrementalValueProvider 单值提供器
为了简单表述,我使用 IncrementalValueProvider 代表 IncrementalValuesProvider 和 IncrementalValueProvider 两个类型的值提供器都实用的情况
如以下代码所示,从 FooInfo1 数据转换为 FooInfo2 数据
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>IncrementalValuesProvider foo1ValuesProvider = ...  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>IncrementalValuesProvider foo2ValuesProvider = foo1ValuesProvider.Select((FooInfo1 info1, CancellationToken token) => new FooInfo2());
复制代码
转换过程中,支持分叉和链式转换。分叉转换,即从一个 IncrementalValueProvider 分叉为多条不同的转换分支,如下面代码所示
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>IncrementalValuesProvider foo1ValuesProvider = ...  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>IncrementalValuesProvider foo2ValuesProvider = foo1ValuesProvider.Select((FooInfo1 info1, CancellationToken token) => new FooInfo2());  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>IncrementalValuesProvider foo3ValuesProvider = foo1ValuesProvider.Select((FooInfo1 info1, CancellationToken token) => new FooInfo3());
复制代码
可见 foo2ValuesProvider 和 foo3ValuesProvider 来源于共同的 foo1ValuesProvider 数据源。这在多个不同的业务逻辑存在共有转换时非常有用,可以更多程度地举行复用计算

链式转换即一级级举行转换
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>IncrementalValuesProvider foo1ValuesProvider = ...  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>IncrementalValuesProvider foo2ValuesProvider = foo1ValuesProvider.Select((FooInfo1 info1, CancellationToken token) => new FooInfo2());  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>IncrementalValuesProvider foo3ValuesProvider = foo2ValuesProvider.Select((FooInfo2 info2, CancellationToken token) => new FooInfo3());
复制代码

Select Many

方法签名:
  1. // 1 转 多
  2. // 多 转 多
  3. public static IncrementalValuesProvider<TResult> SelectMany<TSource, TResult>(this IncrementalValue[s]Provider<TSource> source, Func<TSource, CancellationToken, IEnumerable<TResult>> selector);
复制代码
如以下代码所示,先从 IncrementalValueProvider 单值提供器,调用 SelectMany 举行单转多,获取到 IncrementalValuesProvider 多值提供器。再继承对 IncrementalValuesProvider 多值提供器调用 SelectMany 举行多转多获取到 IncrementalValuesProvider 多值提供器
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>IncrementalValueProvider foo1ValueProvider = ...  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>IncrementalValuesProvider foo2ValuesProvider = foo1ValueProvider.SelectMany  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>(  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>    (FooInfo1 info1, CancellationToken token) =>  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>    {  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>var n = info1.Number;  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>var list = new List();  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>for (int i = 0; i < n; i++)  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>{  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>  <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>    list.Add(new FooInfo2());  <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>  <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>}  <ItemGroup>
  36.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  37.   </ItemGroup>  <ItemGroup>
  38.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  39.   </ItemGroup>return list;  <ItemGroup>
  40.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  41.   </ItemGroup>    }  <ItemGroup>
  42.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  43.   </ItemGroup>);  <ItemGroup>
  44.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  45.   </ItemGroup>IncrementalValuesProvider foo3ValuesProvider = foo2ValuesProvider.SelectMany  <ItemGroup>
  46.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  47.   </ItemGroup>(  <ItemGroup>
  48.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  49.   </ItemGroup>    (FooInfo2 info2, CancellationToken token) =>  <ItemGroup>
  50.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  51.   </ItemGroup>    {  <ItemGroup>
  52.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  53.   </ItemGroup>  <ItemGroup>
  54.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  55.   </ItemGroup>var list = new List();  <ItemGroup>
  56.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  57.   </ItemGroup>  <ItemGroup>
  58.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  59.   </ItemGroup>for (int i = 0; i < info2.Count; i++)  <ItemGroup>
  60.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  61.   </ItemGroup>  <ItemGroup>
  62.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  63.   </ItemGroup>{  <ItemGroup>
  64.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  65.   </ItemGroup>  <ItemGroup>
  66.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  67.   </ItemGroup>    list.Add(new FooInfo3());  <ItemGroup>
  68.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  69.   </ItemGroup>  <ItemGroup>
  70.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  71.   </ItemGroup>}  <ItemGroup>
  72.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  73.   </ItemGroup>  <ItemGroup>
  74.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  75.   </ItemGroup>return list;  <ItemGroup>
  76.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  77.   </ItemGroup>    }  <ItemGroup>
  78.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  79.   </ItemGroup>);
复制代码
假定 FooInfo1 的 Number 的是 3 的值。每个 FooInfo2 的 Count 也是 3 的值,则颠末以上转换之后,可获取带有 3x3=9 个元素的 IncrementalValuesProvider 多值提供器
从 IncrementalValueProvider 单值提供器,调用 SelectMany 举行单转多,获取到 IncrementalValuesProvider 多值提供器的过程是 1 转多的过程,相对来说很是清晰

对 IncrementalValuesProvider 多值提供器调用 SelectMany 举行多转多获取到 IncrementalValuesProvider 多值提供器的过程,相对来说就比力复杂,如以下的官方附图,每项都可转换为不定数量集合输出

敲黑板,使用 SelectMany 的过程中,也可以附带过滤的作用。如上文所述,每项都可转换为不定数量集合输出,不定数量就意味着也可以返回 0 项。在 SelectMany 实行过滤作用的做法就是将不满足条件的直接过滤掉,甚至返回空集合。因此比力少见 SelectMany(...).Where(...) 的组合,直接就是在 SelectMany 里面内置了 Where 的活了
常见于将 SelectMany 和下文介绍的 Collect 混用,告竣合和分的结果
Where

方法签名:
  1. public static IncrementalValuesProvider<TSource> Where<TSource>(this IncrementalValuesProvider<TSource> source, Func<TSource, bool> predicate);
复制代码
没错,只有多值提供器才有 Where 方法。通过 Where 方法可用来过滤输入源里面符合条件的元素,将符合条件的元素作为输出源内容

如上图官方附图所示,假定输入源有三个,中间一个不满足条件,也就是上面打了叉叉的 Item2 项,则最终只有 Item1 和 Item3 才能流向输出源里
正如大家所熟悉的 Linq 里面的 Select 和 Where 配合一样,在增量源代码生成器这里对这两个的用法和计划实现也都和 Linq 的相同
Collect

方法签名:
  1. IncrementalValueProvider<ImmutableArray<TSource>> Collect<TSource>(this IncrementalValuesProvider<TSource> source);
复制代码
这是一个不用附带任何条件和转换器的方法。用于将一个多值提供器的内容,转换为单值提供器。这个过程中,一旦输入源有任何一项变动,则会重新输出整个新的不可变集合

如以上官方附图所示,通过 Collect 方法将一个多值提供器转换为一个单值提供器,且这个单值提供器提供的单个值就是一个集合
这个 Collect 过程可以以为和 SelectMany 是互逆的过程,即可以从 Collect 由多值提供器转换为一个单值提供器,再从 SelectMany 由单值提供器转换为多值提供器。如以下代码所示
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>IncrementalValuesProvider foo1ValuesProvider = ...;  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>IncrementalValueProvider foo1ArrayValueProvider = foo1ValuesProvider.Collect();  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>IncrementalValuesProvider backToValuesProvider = foo1ArrayValueProvider.SelectMany((ImmutableArray array, CancellationToken token) => array);  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>foo1ValuesProvider = backToValuesProvider;
复制代码
以上代码先使用 Collect 方法,从 IncrementalValuesProvider 多值提供器,转换为带不可变集合的 IncrementalValueProvider 单值提供器
再调用 SelectMany 方法,重新将 IncrementalValueProvider 单值提供器转换为原来的 IncrementalValuesProvider 多值提供器。从以上代码最后一行可以看到,颠末 SelectMany 转换返来的 backToValuesProvider 的类型是完全和 foo1ValuesProvider 一样的,相互赋值都能通过构建
Split

正确来说这只是一个用法,不是一个 API 方法。表示的就是分叉调用,多分支调用。如在 Select 一节中和大家介绍,答应举行分叉转换。事实上,在以上介绍的每个内容里面,每个值提供器,无论是多值提供器还是单值提供器,都可以被多次调用各个方法作为输入源举行消耗。这和 Linq 里面的固有印象有所不同,在 Linq 里面,枚举 IEnumerable 是不支持多次重复消耗的,多次消耗将获取不可控结果。但在源代码生成器这里面,数据源的提供依靠的是缓存失效来驱动,大概称为数据变更驱动。一旦有数据变更,缓存失效,则会一条链路举行传递
咱所编写的对各个值提供器的各种转换逻辑,只是用于写入记载转换链路而已。当数据变更的时候,将会重新开始跑整个链路。在跑的过程中,引入了大量缓存判定,从而最大程度减少实行逻辑量
在演练中,咱也用到了 Split 的功能,即在拿到 IncrementalValuesProvider itemGeneratedCodeResultProvider 数据源时,一路作为 Diagnostic 报告输出,一路作为最终源代码生成的输出

Combine

方法签名:
  1. // 1 对 1 合并
  2. IncrementalValueProvider<(TLeft Left, TRight Right)> Combine<TLeft, TRight>(this IncrementalValueProvider<TLeft> provider1, IncrementalValueProvider<TRight> provider2);
  3. // 多对 1 合并
  4. IncrementalValuesProvider<(TLeft Left, TRight Right)> Combine<TLeft, TRight>(this IncrementalValuesProvider<TLeft> provider1, IncrementalValueProvider<TRight> provider2);
复制代码
和以上的分叉相对,以上的 Split 分叉是将一条值提供器作为多个数据提供源,将一个数据链路拆分为多个数据链路。而 Combine 则是将两个数据链路合并到一个链路。能够支持的合并方式是两个单值提供器的合并,以及一个多值提供器和一个单值提供器的合并
两个单值提供器的合并:

如以上的官方附图,将两个单值提供器的合并,返回结果依然是一个单值提供器。只是返回的输出源里面包罗的是一个元组,其中左右值就是所 Combine 顺序的左右值。如以下代码所示
  1. IncrementalValueProvider<FooInfo1> foo1ValueProvider = ...;
  2. IncrementalValueProvider<FooInfo2> foo2ValueProvider = ...;
  3. IncrementalValueProvider<(FooInfo1 Left, FooInfo2 Right)> foo1AndFoo2CombineValueProvider = foo1ValueProvider.Combine(foo2ValueProvider);
复制代码
以上代码分别将 IncrementalValueProvider 和 IncrementalValueProvider 两个单值提供器举行合并。合并之后得到了 IncrementalValueProvider 的单值提供器
一个多值提供器和一个单值提供器的合并:

如以上的官方附图,最终输出源里面是多值提供器里面的每一项都带着单值提供器里面的内容。即输出源里面的元组的左侧是多值提供器里面的每一项,右侧都是相同的单值提供器里面的元素
那两个多值提供器的合并呢?
敲黑板,在 Combine 方法里面不支持两个多值提供器的合并。因为一旦两个多值提供器举行合并,则一旦出现任何一方某个元素的缓存失效问题,将会有笛卡尔积次的实行风险。只提供一个多值提供器和一个单值提供器的合并,则可以明白让源代码生成器开发者决定其优化方向,即将哪方作为单值提供器
那假定我的业务上就是有两个多值提供器,我确实下一步的逻辑就必要两个多值提供器提供的数据才能完成工作。那此时应该如何开展呢?相信会灵活运用所学知识的伙伴已经想到了方法了。没错,就是将其中一个多值提供器调用 Collect 方法,将其转换为单值提供器,于是就可以继承愉快地调用 Combine 举行一个多值提供器和一个单值提供器的合并。这个过程中,源代码生成器开发者可选用两个多值提供器中量小、变化次数少的一方调用 Collect 转换为单值提供器,从而提供更多的优化结果
以上就是增量源代码生成器的专有基础知识,公道运用好以上的几个数据源处置惩罚方法,即可实现对复杂的数据处置惩罚的同时,减少计算量
演练:源代码专有 Interceptor 技术

颠末了上文的介绍,大家是否对源代码生成器的基础知识有了一定的了解。是否会存在一个错觉,以为源代码生成器最多只是减轻人类程序猿的工作量,但并不能轻易突破人类程序猿难以做到的事情?接下来我将介绍源代码生成器的专有技术 Interceptor 拦截器技术,这是一种源代码生成器专有的技术,可以在构建过程中实行额外的逻辑实现拦截现有代码的功能
或许换个叫法大家会更熟悉这一类型的技术,即 AOP 面向切面编程。焦点差别在于源代码生成器方式的 AOP 是发生在编译阶段,可以做到零反射。且过程中是可以实现到完全的调用转发。即大家举行静态代码阅读的时候,看到的是调用了 A 方法,然而实际构建出来的代码是调用了 B 方法。这种技术在实际开发中非常有用,比如在构建过程中举行日志记载、性能监控、权限控制等等
现在直接使用 Interceptor 技术的就有 ASP.NET Core 的配置和部分日志的等模块功能,详细请参阅 Compile-time configuration source generation - .NET - Microsoft Learn
在本演练中,我将和大家介绍如安在源代码生成器里面使用 Interceptor 技术,实现对现有代码的拦截调用转发。将原本调用 Foo 类型的 WriteLine 方法,转发到调用源代码新生成的代码里面。比如有以下的代码,大家猜猜在本演练里面,实行代码将会输出什么内容
  1. class Program{    static void Main()    {  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>var c = new Foo();  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>c.WriteLine(1);  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>c.WriteLine(2);  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>c.WriteLine(3);    }}class Foo{    public void WriteLine(int message)    {  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>Console.WriteLine($"Foo: {message}");    }}
复制代码
想必大家一看就知道,实行代码将会输出以下内容
  1. Foo: 1
  2. Foo: 2
  3. Foo: 3
复制代码
然而我告诉大家,以上代码实行的输出将会看我在源代码生成器里面的生成代码怎么写,静态阅读代码是看不出来的。接下来我将和大家介绍如何实现这个功能
为了方便大家拉取代码,我依然是新建两个项目,分别是名为 JuqawhicaqarLairciwholeni 的控制台项目,和名为 JuqawhicaqarLairciwholeni.Analyzer 的分析器项目。项目搭建方式和上文介绍的一样,不再赘述
在本演练任务里面,咱必要拦截所有对 Foo 类型的 WriteLine 方法的调用,将其转换为源代码生成器所生成的新的代码
开始之前先介绍一下 C# 12 引入的 Interceptor 拦截器技术,拦截器技术的焦点是通过一个 InterceptsLocationAttribute 特性标志一个方法。被标志的方法可以拦截在 InterceptsLocationAttribute 特性上所设置的所要拦截的代码的调用。如以下代码所示,在名为 FooInterceptor 类型的 InterceptorMethod1 方法上,标志了 InterceptsLocationAttribute 特性,注明白拦截 Program.cs 文件上的某行代码
  1.     static partial class FooInterceptor    {  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>// C:\lindexi\Code\JuqawhicaqarLairciwholeni\JuqawhicaqarLairciwholeni\Program.cs(8,11)  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>[InterceptsLocation(version: 1, data: "PSnZx2mpBdT444AVZJmMJX8AAABQcm9ncmFtLmNz")]  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>public static void InterceptorMethod1(this global::JuqawhicaqarLairciwholeni.Foo foo, int param)  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>{  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>    Console.WriteLine($"Interceptor1: lindexi is doubi");  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>}    }
复制代码
这里能够看到的是在 InterceptsLocationAttribute 特性上标志了人类难明的 PSnZx2mpBdT444AVZJmMJX8AAABQcm9ncmFtLmNz 字符串内容。这实在是对 C:\lindexi\Code\JuqawhicaqarLairciwholeni\JuqawhicaqarLairciwholeni\Program.cs(8,11) 的一个标识,这个标识是由源代码生成器里面的 SemanticModel 的 GetInterceptableLocation 方法提供的
假定 C:\lindexi\Code\JuqawhicaqarLairciwholeni\JuqawhicaqarLairciwholeni\Program.cs(8,11) 对应的代码就是 c.WriteLine(1); 这一行代码。那么在实行代码的时候,将会输出以下内容
  1. Interceptor1: lindexi is doubi
复制代码
而不是原本预期的 Foo: 1 的输出内容。这就是 Interceptor 拦截器技术的焦点,通过拦截器技术,可以在构建过程中实行额外的逻辑实现拦截现有代码的功能

简单了解了 Interceptor 拦截器技术的焦点,在本演练中将开始和大家介绍如何实现这个功能,将原本调用 Foo 类型的 WriteLine 方法,转发到调用源代码新生成的代码里面。以下是我的实现结果,将原本代码里面临 Foo 类型的 WriteLine 方法的三个调用,分别转发到源代码生成器所生成的三个不同的方法里面,如下图所示

通过本演练的源代码生成器所处置惩罚之后,通过 ILSpy 工具查看生成的 dll 文件,可见最终的生成代码是调用了 FooInterceptor 的三个生成的方法,完全不是静态代码所见的调用 Foo 类型的 WriteLine 方法

即在这个过程里面,所发生的所有科技都在构建之中完成,不会在运行时发生任何额外的调用
在 JuqawhicaqarLairciwholeni.Analyzer 项目里面新建名为 FooIncrementalGenerator 的继承 IIncrementalGenerator 的类型,其代码如下
  1. [Generator(LanguageNames.CSharp)]public class FooIncrementalGenerator : IIncrementalGenerator{    public void Initialize(IncrementalGeneratorInitializationContext context)    {  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>...    }}
复制代码
为了分析所有对 Foo 类型的 WriteLine 方法的调用,必要找到所有 InvocationExpressionSyntax 类型的语法点。这些语法点就是各个代码里面调用方法等的地方了,再进一步判断调用的是不是名为 WriteLine 的方法,语法判断部分的工作就完成了。也许有伙伴读到这里会有疑问,为什么只是判断调用的是不是名为 WriteLine 的方法,而不再继承判断是不是 Foo 类型的 WriteLine 方法。这是因为在语法判断里面,我们是无法直接访问到调用的具体类型的,语法层面上只能猜,而猜不如放到语义过程举行正确判断
  1. [Generator(LanguageNames.CSharp)]public class FooIncrementalGenerator : IIncrementalGenerator{    public void Initialize(IncrementalGeneratorInitializationContext context)    {  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>    context.SyntaxProvider.CreateSyntaxProvider(  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>    (node, _) =>  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>    {  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>if (node is InvocationExpressionSyntax invocationExpressionSyntax)  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>{  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>    if (invocationExpressionSyntax.Expression is MemberAccessExpressionSyntax memberAccessExpressionSyntax)  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>    {  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>// 这是一个调用名为 WriteLine 的方法代码,但就不知道具体是谁的 WriteLine 了。语法过程中是无法知道具体的类型是哪个的  <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>  <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>  <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>// 比如 Foo a = ...; a.WriteLine(...);  <ItemGroup>
  36.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  37.   </ItemGroup>  <ItemGroup>
  38.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  39.   </ItemGroup>  <ItemGroup>
  40.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  41.   </ItemGroup>// 或 Foo b = ...; b.WriteLine(...);  <ItemGroup>
  42.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  43.   </ItemGroup>  <ItemGroup>
  44.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  45.   </ItemGroup>  <ItemGroup>
  46.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  47.   </ItemGroup>// 此时最多在语法层面只判断出是 WriteLine 方法,进一步判断就交给语义过程了  <ItemGroup>
  48.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  49.   </ItemGroup>  <ItemGroup>
  50.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  51.   </ItemGroup>  <ItemGroup>
  52.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  53.   </ItemGroup>return memberAccessExpressionSyntax.Name.Identifier.Text == "WriteLine";  <ItemGroup>
  54.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  55.   </ItemGroup>  <ItemGroup>
  56.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  57.   </ItemGroup>    }  <ItemGroup>
  58.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  59.   </ItemGroup>  <ItemGroup>
  60.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  61.   </ItemGroup>}  <ItemGroup>
  62.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  63.   </ItemGroup>  <ItemGroup>
  64.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  65.   </ItemGroup>return false;  <ItemGroup>
  66.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  67.   </ItemGroup>    },  <ItemGroup>
  68.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  69.   </ItemGroup>    (syntaxContext, _) =>  <ItemGroup>
  70.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  71.   </ItemGroup>    {  <ItemGroup>
  72.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  73.   </ItemGroup>  <ItemGroup>
  74.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  75.   </ItemGroup>...  <ItemGroup>
  76.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  77.   </ItemGroup>    });  <ItemGroup>
  78.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  79.   </ItemGroup>...    }}
复制代码
在语义转换里面,进一步判断所调用的是不是 Foo 类型的 WriteLine 方法,即判断当前调用的 WriteLine 方法是不是在 Foo 类型上面界说的。这里使用 SemanticModel 的 GetSymbolInfo 方法获取到调用的方法的符号信息,接着判断方法符号所在的类型是不是 Foo 类型
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>    context.SyntaxProvider.CreateSyntaxProvider(  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>    (node, _) =>  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>    {  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>...  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>    },  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>    (syntaxContext, _) =>  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>    {  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>var symbolInfo = syntaxContext.SemanticModel.GetSymbolInfo(syntaxContext.Node);  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>if (symbolInfo.Symbol is not IMethodSymbol methodSymbol  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>    // 以下这句判断纯属多余,因为语法过程中已经判断了是 WriteLine 方法  <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>  <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>    || methodSymbol.Name != "WriteLine")  <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>  <ItemGroup>
  36.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  37.   </ItemGroup>{  <ItemGroup>
  38.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  39.   </ItemGroup>  <ItemGroup>
  40.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  41.   </ItemGroup>    return default;  <ItemGroup>
  42.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  43.   </ItemGroup>  <ItemGroup>
  44.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  45.   </ItemGroup>}  <ItemGroup>
  46.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  47.   </ItemGroup>  <ItemGroup>
  48.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  49.   </ItemGroup>// 语义过程继承判断具体是否 Foo 类型的 WriteLine 方法  <ItemGroup>
  50.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  51.   </ItemGroup>  <ItemGroup>
  52.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  53.   </ItemGroup>var className = methodSymbol.ContainingType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);  <ItemGroup>
  54.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  55.   </ItemGroup>  <ItemGroup>
  56.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  57.   </ItemGroup>if (className != "global::JuqawhicaqarLairciwholeni.Foo")  <ItemGroup>
  58.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  59.   </ItemGroup>  <ItemGroup>
  60.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  61.   </ItemGroup>{  <ItemGroup>
  62.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  63.   </ItemGroup>  <ItemGroup>
  64.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  65.   </ItemGroup>    return default;  <ItemGroup>
  66.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  67.   </ItemGroup>  <ItemGroup>
  68.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  69.   </ItemGroup>}  <ItemGroup>
  70.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  71.   </ItemGroup>  <ItemGroup>
  72.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  73.   </ItemGroup>...  <ItemGroup>
  74.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  75.   </ItemGroup>    })
复制代码
为了调用 SemanticModel 的 GetInterceptableLocation 方法获取传入到 InterceptsLocationAttribute 特性的必要参数,这里通过 syntaxContext.Node 属性拿到当前正在发起方法调用的 InvocationExpressionSyntax 语法节点。接着调用 GetInterceptableLocation 方法获取到拦截器的位置信息
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>...  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>var invocationExpressionSyntax = (InvocationExpressionSyntax) syntaxContext.Node;  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>...
复制代码
现在 SemanticModel 的 GetInterceptableLocation 方法还被标志了实行性,调用此方法之前必要使用 #pragma warning disable RSEXPERIMENTAL002 开启实行性功能
  1.   var invocationExpressionSyntax = (InvocationExpressionSyntax) syntaxContext.Node;
  2. #pragma warning disable RSEXPERIMENTAL002 // 实验性警告,忽略即可
  3.   InterceptableLocation interceptableLocation = syntaxContext.SemanticModel.GetInterceptableLocation(invocationExpressionSyntax)!;
复制代码
此时拿到的 InterceptableLocation 对象就是包罗了将要拦截的代码的具体信息,包括具体是哪个文件的哪行哪列代码,且这个过程里面还包罗了代码文件的摘要信息,确保将要拦截替换的代码是符合源代码生成器在生成过程中所预期的。如以下代码尝试拿到 DisplayLocation 字符串信息内容
  1.   var displayLocation = interceptableLocation.DisplayLocation;
复制代码
这里的 displayLocation 字符串的大概内容是对应的代码的路径和所在行列信息,如以下代码所示
  1. C:\lindexi\Code\JuqawhicaqarLairciwholeni\JuqawhicaqarLairciwholeni\Program.cs(9,11)
复制代码
为了演示结果,我这里还尝试使用语法语义方式读取在 Program.cs 里面调用 WriteLine 方法的参数值,即调用 WriteLine 方法的参数值是多少。这里使用 invocationExpressionSyntax.ArgumentList.Arguments 属性获取到所有的参数列表,再取其首个参数。最后配合语义获取传入的常量值
  1. ArgumentSyntax argumentSyntax = invocationExpressionSyntax.ArgumentList.Arguments.First();
  2. var argument = (int)syntaxContext.SemanticModel.GetConstantValue(argumentSyntax.Expression).Value!;
复制代码
以上代码仅仅用于演示哈,因为这要求原本的代码里面传入参数确实就是常量值。在实际的代码里面,传入的参数可能是变量、表达式等等,不能像本演练里面这样直接获取到常量值
完成准备工作之后,就可以开始来生成代码啦
依然是为了让我的博客引擎开森,我将以下代码的两个连在一起的花括号替换为全角的花括号
  1. var generatedCode =    $$"""      using System.Runtime.CompilerServices;  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>    namespace Foo_JuqawhicaqarLairciwholeni      {  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>  static partial class FooInterceptor  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>  {  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>      // {{displayLocation}}  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>      [InterceptsLocation(version: {{interceptableLocation.Version}}, data: "{{interceptableLocation.Data}}")]  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>      public static void InterceptorMethod{{argument}}(this {{className}} foo, int param)  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>      {  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>  Console.WriteLine($"Interceptor{{argument}}: lindexi is doubi");  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>      }  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>  }      }      namespace System.Runtime.CompilerServices      {  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>  [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>  file sealed class InterceptsLocationAttribute : Attribute  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>  {  <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>      public InterceptsLocationAttribute(int version, string data)  <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>      {  <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>  <ItemGroup>
  36.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  37.   </ItemGroup>  _ = version;  <ItemGroup>
  38.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  39.   </ItemGroup>  <ItemGroup>
  40.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  41.   </ItemGroup>  _ = data;  <ItemGroup>
  42.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  43.   </ItemGroup>      }  <ItemGroup>
  44.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  45.   </ItemGroup>  }      }      """;
复制代码

如以上代码所示,可以看到将 displayLocation 作为解释放在拦截方法上方,如此即可在阅读源代码生成器所生成的代码的时候,可以看到被拦截的代码的位置信息。接着再将读取到的传入参数信息拼接成为拦截方法的方法名以及作为拦截方法的输出内容
由于 InterceptsLocationAttribute 本身也只是一个给编译器看的特性,不在 Runtime 里面界说,且编译器也不关心这个类型的可见性,编译器只关心特性的全名,即定名空间和类型名符合要求即可。那就直接开森地使用 file 关键字举行修饰,放入到对应的生成的代码所在文件里面。这样也可以防止界说的 InterceptsLocationAttribute 特性去污染其他源代码生成器或项目里面的代码
完成了生成代码的拼接,为了将其举行返回,这里再界说一个名为 GeneratedCodeInfo 的结构体,代码如下
  1. readonly record struct GeneratedCodeInfo(string GeneratedCode, string Name);
复制代码
将其作为返回值返回,且再叠加一个 Where 方法过滤掉不符合条件的情况
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>IncrementalValuesProvider sourceProvider = context.SyntaxProvider.CreateSyntaxProvider(  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>    (node, _) =>  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>    {  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>...  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>    },  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>    (syntaxContext, _) =>  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>    {  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>var invocationExpressionSyntax = (InvocationExpressionSyntax) syntaxContext.Node;  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>ArgumentSyntax argumentSyntax = invocationExpressionSyntax.ArgumentList.Arguments.First();  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>var argument = (int) syntaxContext.SemanticModel.GetConstantValue(argumentSyntax.Expression).Value!;  <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>  <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>var generatedCode = ...  <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>  <ItemGroup>
  36.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  37.   </ItemGroup>return new GeneratedCodeInfo(generatedCode, $"FooInterceptor{argument}.cs");  <ItemGroup>
  38.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  39.   </ItemGroup>    })  <ItemGroup>
  40.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  41.   </ItemGroup>    .Where(t => t != default);
复制代码
最后将 sourceProvider 值提供器注册到 RegisterImplementationSourceOutput 方法上即可。为什么是注册到 RegisterImplementationSourceOutput 方法上呢?因为这里面只是包罗了具体的实现逻辑,没有任何可以参与语法分析的界说部分,也不会被外部所访问,放入到 RegisterImplementationSourceOutput 方法上十分合适
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>context.RegisterImplementationSourceOutput(sourceProvider,  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>   (productionContext, provider) =>  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>   {  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>       productionContext.AddSource(provider.Name, provider.GeneratedCode);  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>   });
复制代码
通过以上的源代码生成器的代码,即可实现本演练中的拦截结果。最后尝试运行一下 JuqawhicaqarLairciwholeni 控制台项目,可看到输出内容是
  1. Interceptor1: lindexi is doubi
  2. Interceptor2: lindexi is doubi
  3. Interceptor3: lindexi is doubi
复制代码
这项 Interceptor 拦截器技术的介绍就到这里,拦截器技术现在还是有很多争议的,焦点一点是破坏原本的静态代码阅读能力。静态阅读代码,不运行不构建时,所见的代码以为的运行结果不等于最终实行结果。这将会给很多开发者带来困惑,甚至可能被用于恶意代码的隐藏。但是在某些场景下,拦截器技术是非常有用的,比如在构建过程中举行日志记载、性能监控、权限控制等等,将原本影响性能的代码使用拦截器重新实现生成,不破坏原本代码结构等等
整个使用 Interceptor 拦截器的源代码生成器的代码如下,同样是为了让我的博客引擎开森,我将以下代码的两个连在一起的花括号替换为全角的花括号
  1. [Generator(LanguageNames.CSharp)]public class FooIncrementalGenerator : IIncrementalGenerator{    public void Initialize(IncrementalGeneratorInitializationContext context)    {  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>IncrementalValuesProvider sourceProvider = context.SyntaxProvider.CreateSyntaxProvider(  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>    (node, _) =>  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>    {  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>if (node is InvocationExpressionSyntax invocationExpressionSyntax)  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>{  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>    if (invocationExpressionSyntax.Expression is MemberAccessExpressionSyntax memberAccessExpressionSyntax)  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>    {  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>// 这是一个调用名为 WriteLine 的方法代码,但就不知道具体是谁的 WriteLine 了。语法过程中是无法知道具体的类型是哪个的  <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>  <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>  <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>// 比如 Foo a = ...; a.WriteLine(...);  <ItemGroup>
  36.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  37.   </ItemGroup>  <ItemGroup>
  38.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  39.   </ItemGroup>  <ItemGroup>
  40.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  41.   </ItemGroup>// 或 Foo b = ...; b.WriteLine(...);  <ItemGroup>
  42.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  43.   </ItemGroup>  <ItemGroup>
  44.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  45.   </ItemGroup>  <ItemGroup>
  46.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  47.   </ItemGroup>// 此时最多在语法层面只判断出是 WriteLine 方法,进一步判断就交给语义过程了  <ItemGroup>
  48.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  49.   </ItemGroup>  <ItemGroup>
  50.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  51.   </ItemGroup>  <ItemGroup>
  52.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  53.   </ItemGroup>return memberAccessExpressionSyntax.Name.Identifier.Text == "WriteLine";  <ItemGroup>
  54.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  55.   </ItemGroup>  <ItemGroup>
  56.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  57.   </ItemGroup>    }  <ItemGroup>
  58.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  59.   </ItemGroup>  <ItemGroup>
  60.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  61.   </ItemGroup>}  <ItemGroup>
  62.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  63.   </ItemGroup>  <ItemGroup>
  64.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  65.   </ItemGroup>return false;  <ItemGroup>
  66.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  67.   </ItemGroup>    },  <ItemGroup>
  68.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  69.   </ItemGroup>    (syntaxContext, _) =>  <ItemGroup>
  70.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  71.   </ItemGroup>    {  <ItemGroup>
  72.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  73.   </ItemGroup>  <ItemGroup>
  74.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  75.   </ItemGroup>var symbolInfo = syntaxContext.SemanticModel.GetSymbolInfo(syntaxContext.Node);  <ItemGroup>
  76.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  77.   </ItemGroup>  <ItemGroup>
  78.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  79.   </ItemGroup>if (symbolInfo.Symbol is not IMethodSymbol methodSymbol  <ItemGroup>
  80.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  81.   </ItemGroup>  <ItemGroup>
  82.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  83.   </ItemGroup>    // 以下这句判断纯属多余,因为语法过程中已经判断了是 WriteLine 方法  <ItemGroup>
  84.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  85.   </ItemGroup>  <ItemGroup>
  86.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  87.   </ItemGroup>    || methodSymbol.Name != "WriteLine")  <ItemGroup>
  88.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  89.   </ItemGroup>  <ItemGroup>
  90.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  91.   </ItemGroup>{  <ItemGroup>
  92.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  93.   </ItemGroup>  <ItemGroup>
  94.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  95.   </ItemGroup>    return default(GeneratedCodeInfo);  <ItemGroup>
  96.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  97.   </ItemGroup>  <ItemGroup>
  98.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  99.   </ItemGroup>}  <ItemGroup>
  100.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  101.   </ItemGroup>  <ItemGroup>
  102.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  103.   </ItemGroup>// 语义过程继承判断具体是否 Foo 类型的 WriteLine 方法  <ItemGroup>
  104.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  105.   </ItemGroup>  <ItemGroup>
  106.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  107.   </ItemGroup>var className = methodSymbol.ContainingType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);  <ItemGroup>
  108.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  109.   </ItemGroup>  <ItemGroup>
  110.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  111.   </ItemGroup>if (className != "global::JuqawhicaqarLairciwholeni.Foo")  <ItemGroup>
  112.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  113.   </ItemGroup>  <ItemGroup>
  114.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  115.   </ItemGroup>{  <ItemGroup>
  116.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  117.   </ItemGroup>  <ItemGroup>
  118.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  119.   </ItemGroup>    return default(GeneratedCodeInfo);  <ItemGroup>
  120.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  121.   </ItemGroup>  <ItemGroup>
  122.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  123.   </ItemGroup>}  <ItemGroup>
  124.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  125.   </ItemGroup>  <ItemGroup>
  126.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  127.   </ItemGroup>/*  <ItemGroup>
  128.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  129.   </ItemGroup>  <ItemGroup>
  130.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  131.   </ItemGroup>   class Foo  <ItemGroup>
  132.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  133.   </ItemGroup>  <ItemGroup>
  134.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  135.   </ItemGroup>   {  <ItemGroup>
  136.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  137.   </ItemGroup>  <ItemGroup>
  138.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  139.   </ItemGroup>       public void WriteLine(int message)  <ItemGroup>
  140.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  141.   </ItemGroup>  <ItemGroup>
  142.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  143.   </ItemGroup>       {  <ItemGroup>
  144.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  145.   </ItemGroup>  <ItemGroup>
  146.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  147.   </ItemGroup>  <ItemGroup>
  148.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  149.   </ItemGroup>   Console.WriteLine($"Foo: {message}");  <ItemGroup>
  150.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  151.   </ItemGroup>  <ItemGroup>
  152.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  153.   </ItemGroup>       }  <ItemGroup>
  154.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  155.   </ItemGroup>  <ItemGroup>
  156.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  157.   </ItemGroup>   }  <ItemGroup>
  158.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  159.   </ItemGroup>  <ItemGroup>
  160.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  161.   </ItemGroup> */  <ItemGroup>
  162.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  163.   </ItemGroup>  <ItemGroup>
  164.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  165.   </ItemGroup>var invocationExpressionSyntax = (InvocationExpressionSyntax) syntaxContext.Node;  <ItemGroup>
  166.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  167.   </ItemGroup>  <ItemGroup>
  168.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  169.   </ItemGroup>ArgumentSyntax argumentSyntax = invocationExpressionSyntax.ArgumentList.Arguments.First();  <ItemGroup>
  170.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  171.   </ItemGroup>  <ItemGroup>
  172.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  173.   </ItemGroup>var argument = (int)syntaxContext.SemanticModel.GetConstantValue(argumentSyntax.Expression).Value!;#pragma warning disable RSEXPERIMENTAL002 // 实行性告诫,忽略即可  <ItemGroup>
  174.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  175.   </ItemGroup>  <ItemGroup>
  176.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  177.   </ItemGroup>var interceptableLocation = syntaxContext.SemanticModel.GetInterceptableLocation(invocationExpressionSyntax)!;  <ItemGroup>
  178.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  179.   </ItemGroup>  <ItemGroup>
  180.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  181.   </ItemGroup>var displayLocation = interceptableLocation.GetDisplayLocation();  <ItemGroup>
  182.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  183.   </ItemGroup>  <ItemGroup>
  184.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  185.   </ItemGroup>var generatedCode =  <ItemGroup>
  186.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  187.   </ItemGroup>  <ItemGroup>
  188.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  189.   </ItemGroup>    $$"""  <ItemGroup>
  190.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  191.   </ItemGroup>  <ItemGroup>
  192.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  193.   </ItemGroup>      using System.Runtime.CompilerServices;  <ItemGroup>
  194.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  195.   </ItemGroup>  <ItemGroup>
  196.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  197.   </ItemGroup>  <ItemGroup>
  198.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  199.   </ItemGroup>  <ItemGroup>
  200.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  201.   </ItemGroup>  <ItemGroup>
  202.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  203.   </ItemGroup>    namespace Foo_JuqawhicaqarLairciwholeni  <ItemGroup>
  204.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  205.   </ItemGroup>  <ItemGroup>
  206.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  207.   </ItemGroup>      {  <ItemGroup>
  208.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  209.   </ItemGroup>  <ItemGroup>
  210.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  211.   </ItemGroup>  <ItemGroup>
  212.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  213.   </ItemGroup>  static partial class FooInterceptor  <ItemGroup>
  214.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  215.   </ItemGroup>  <ItemGroup>
  216.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  217.   </ItemGroup>  <ItemGroup>
  218.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  219.   </ItemGroup>  {  <ItemGroup>
  220.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  221.   </ItemGroup>  <ItemGroup>
  222.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  223.   </ItemGroup>  <ItemGroup>
  224.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  225.   </ItemGroup>      // {{displayLocation}}  <ItemGroup>
  226.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  227.   </ItemGroup>  <ItemGroup>
  228.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  229.   </ItemGroup>  <ItemGroup>
  230.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  231.   </ItemGroup>      [InterceptsLocation(version: {{interceptableLocation.Version}}, data: "{{interceptableLocation.Data}}")]  <ItemGroup>
  232.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  233.   </ItemGroup>  <ItemGroup>
  234.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  235.   </ItemGroup>  <ItemGroup>
  236.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  237.   </ItemGroup>      public static void InterceptorMethod{{argument}}(this {{className}} foo, int param)  <ItemGroup>
  238.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  239.   </ItemGroup>  <ItemGroup>
  240.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  241.   </ItemGroup>  <ItemGroup>
  242.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  243.   </ItemGroup>      {  <ItemGroup>
  244.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  245.   </ItemGroup>  <ItemGroup>
  246.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  247.   </ItemGroup>  <ItemGroup>
  248.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  249.   </ItemGroup>  <ItemGroup>
  250.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  251.   </ItemGroup>  Console.WriteLine($"Interceptor{{argument}}: lindexi is doubi");  <ItemGroup>
  252.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  253.   </ItemGroup>  <ItemGroup>
  254.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  255.   </ItemGroup>  <ItemGroup>
  256.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  257.   </ItemGroup>      }  <ItemGroup>
  258.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  259.   </ItemGroup>  <ItemGroup>
  260.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  261.   </ItemGroup>  <ItemGroup>
  262.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  263.   </ItemGroup>  }  <ItemGroup>
  264.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  265.   </ItemGroup>  <ItemGroup>
  266.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  267.   </ItemGroup>      }  <ItemGroup>
  268.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  269.   </ItemGroup>  <ItemGroup>
  270.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  271.   </ItemGroup>      namespace System.Runtime.CompilerServices  <ItemGroup>
  272.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  273.   </ItemGroup>  <ItemGroup>
  274.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  275.   </ItemGroup>      {  <ItemGroup>
  276.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  277.   </ItemGroup>  <ItemGroup>
  278.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  279.   </ItemGroup>  <ItemGroup>
  280.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  281.   </ItemGroup>  [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]  <ItemGroup>
  282.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  283.   </ItemGroup>  <ItemGroup>
  284.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  285.   </ItemGroup>  <ItemGroup>
  286.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  287.   </ItemGroup>  file sealed class InterceptsLocationAttribute : Attribute  <ItemGroup>
  288.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  289.   </ItemGroup>  <ItemGroup>
  290.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  291.   </ItemGroup>  <ItemGroup>
  292.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  293.   </ItemGroup>  {  <ItemGroup>
  294.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  295.   </ItemGroup>  <ItemGroup>
  296.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  297.   </ItemGroup>  <ItemGroup>
  298.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  299.   </ItemGroup>      public InterceptsLocationAttribute(int version, string data)  <ItemGroup>
  300.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  301.   </ItemGroup>  <ItemGroup>
  302.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  303.   </ItemGroup>  <ItemGroup>
  304.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  305.   </ItemGroup>      {  <ItemGroup>
  306.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  307.   </ItemGroup>  <ItemGroup>
  308.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  309.   </ItemGroup>  <ItemGroup>
  310.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  311.   </ItemGroup>  <ItemGroup>
  312.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  313.   </ItemGroup>  _ = version;  <ItemGroup>
  314.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  315.   </ItemGroup>  <ItemGroup>
  316.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  317.   </ItemGroup>  <ItemGroup>
  318.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  319.   </ItemGroup>  <ItemGroup>
  320.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  321.   </ItemGroup>  _ = data;  <ItemGroup>
  322.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  323.   </ItemGroup>  <ItemGroup>
  324.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  325.   </ItemGroup>  <ItemGroup>
  326.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  327.   </ItemGroup>      }  <ItemGroup>
  328.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  329.   </ItemGroup>  <ItemGroup>
  330.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  331.   </ItemGroup>  <ItemGroup>
  332.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  333.   </ItemGroup>  }  <ItemGroup>
  334.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  335.   </ItemGroup>  <ItemGroup>
  336.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  337.   </ItemGroup>      }  <ItemGroup>
  338.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  339.   </ItemGroup>  <ItemGroup>
  340.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  341.   </ItemGroup>      """;  <ItemGroup>
  342.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  343.   </ItemGroup>  <ItemGroup>
  344.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  345.   </ItemGroup>return new GeneratedCodeInfo(generatedCode, $"FooInterceptor{argument}.cs");  <ItemGroup>
  346.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  347.   </ItemGroup>    })  <ItemGroup>
  348.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  349.   </ItemGroup>    .Where(t => t != default);  <ItemGroup>
  350.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  351.   </ItemGroup>context.RegisterImplementationSourceOutput(sourceProvider,  <ItemGroup>
  352.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  353.   </ItemGroup>   (productionContext, provider) =>  <ItemGroup>
  354.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  355.   </ItemGroup>   {  <ItemGroup>
  356.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  357.   </ItemGroup>       productionContext.AddSource(provider.Name, provider.GeneratedCode);  <ItemGroup>
  358.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  359.   </ItemGroup>   });    }}readonly record struct GeneratedCodeInfo(string GeneratedCode, string Name);
复制代码
更多拦截器技术的介绍请参阅: Interceptors document
本演练代码放在 githubgitee 上,可以使用如下命令行拉取代码。我整个代码堆栈比力庞大,使用以下命令行可以举行部分拉取,拉取速率比力快
先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
  1. git init
  2. git remote add origin https://gitee.com/lindexi/lindexi_gd.git
  3. git pull origin f242a711c0f2fb65a01406a36042d87fc314cb51
复制代码
以上使用的是国内的 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继承输入以下代码,将 gitee 源换成 github 源举行拉取代码。如果依然拉取不到代码,可以发邮件向我要代码
  1. git remote remove origin
  2. git remote add origin https://github.com/lindexi/lindexi_gd.git
  3. git pull origin f242a711c0f2fb65a01406a36042d87fc314cb51
复制代码
获取代码之后,进入 Roslyn/JuqawhicaqarLairciwholeni 文件夹,即可获取到源代码
以上介绍的都是从代码入手,通过对现有的代码举行分析而生成新的代码。大家是否好奇其输入源还有没有其他方式。接下来将通过演练的方式和大家分别介绍从 csproj 等项目属性配置以及通过其他非代码文件的方式举行源代码生成
演练:将构建时间和自界说配置写入源代码

本次演练的任务是将构建时间和自界说配置写入源代码。这个任务的背景是,有时候我们想要直接从代码里面读取一些构建时的信息,比如构建时间呀、一些自界说配置呀等等。这个任务的目标是让大家了解如何从 csproj 项目文件里面读取属性配置,以及如何将这些属性配置写入源代码
再细化一下,我盼望的是能够在源代码里面写出以下代码
  1. Console.WriteLine($"BuildAt={BuildInformation.BuildAt}");
  2. Console.WriteLine($"Platform={BuildInformation.Platform}");
  3. Console.WriteLine($"Configuration={BuildInformation.Configuration}");
复制代码
运行的输出内容大概如下
  1. BuildAt=2025/3/9 13:41:29
  2. Platform=AnyCpu
  3. Configuration=Release
复制代码
以上的 BuildInformation 类型就是一个由源代码生成器生成的类,里面包罗了构建时间、平台和配置信息
在源代码生成器里面,不必要直接碰触 csproj 项目文件的读取,取而代之的是从 CompilationProvider 值提供器里面获取到项目标编译信息
这里也能和大家证实的是,作为源代码生成器的输入源,不但仅是代码,还可以是其他的一些信息。这里的信息是编译信息,也可以是其他的一些信息,比如额外的文件等等信息
此演练的焦点实现方法如下,起首是从 CompilationProvider 值提供器里面获取到项目标编译信息,接着就可以愉快地写入生成的代码啦,非常简单。这里我就跳过了项目创建的步调,直接到焦点代码的实现
  1.     [Generator(LanguageNames.CSharp)]    public class FooGenerator : IIncrementalGenerator    {  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>public void Initialize(IncrementalGeneratorInitializationContext context)  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>{  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>    var compilerOptions = context.CompilationProvider.Select((s, _) => s.Options);  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>}    }
复制代码
以上的 compilerOptions 就包罗了构建配置信息,如 Platform 和 Configuration 等信息。固然了以上的这句 Select 纯属卖萌,没有挑拣出任何有用信息,也没有做转换,不符合最佳实践,只能作为演示
接下来就直接将 compilerOptions 放入到 RegisterSourceOutput 方法里面,举行生成源代码,如以下代码
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>    context.RegisterSourceOutput(compilerOptions, static (productionContext, options) =>  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>    {  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>var code = $@"using System;using System.Globalization;public static class BuildInformation{{    ///     /// Returns the build date (UTC).    ///     public static readonly DateTime BuildAt = DateTime.ParseExact(""{DateTime.UtcNow:O}"", ""O"", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind);    ///     /// Returns the platform.    ///     public const string Platform = ""{options.Platform}"";    ///     /// Returns the configuration.    ///     public const string Configuration = ""{options.OptimizationLevel}"";}}";  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>productionContext.AddSource("LinkDotNet.BuildInformation.g", code);  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>    });
复制代码
同样地,为了让我的博客引擎开森,以上代码部分花括号被我替换为了全角花括号。大家在使用的时候必要将全角花括号替换为半角花括号
这就完成了生成了一个名为 BuildInformation 的静态类,且此静态类还没有包罗在任何的定名空间里面
大家如果对更多细节感爱好,还请参阅 IIncrementalGenerator 增量 Source Generator 生成代码应用 将构建时间写入源代码
以上就是采用 CompilationProvider 间接读取 csproj 项目文件的属性配置,将自界说配置内容写入源代码的过程。接下来将继承通过演练的方式,告诉大家如安在分析器项目里面读取其他非代码文件的内容
演练:写一个 禁用API调用 分析器

前面介绍的都是围绕着编写源代码生成器展开的,本章将介绍使用专用分析器技术编写一个纯分析器。这个过程中也会介绍如何读取其他非代码文件的内容作为输入源的方式
在前面的章节有和大家演示过调用 ReportDiagnostic 给出分析报告的方法。在源代码生成器里面给出的分析报告的步调是举行语法和语义的分析,判断符合某个条件,则给出分析报告的结果。整个过程是非常公式化的。只不过在源代码生成器步调里面更加侧重如何举行生成代码,从而必要许多细节的分析语法和语义的过程。专用的分析器则可以更大程度地省略掉这些琐碎的步调,让大家可以使用根据方便的高级的 API 举行快速的分析语法语义
为了能够更好地介绍专用分析器,在本章演练过程中,咱将带着这样的一个任务开始:编写一个禁用API调用分析器
具体的任务需求细节是根据配置的禁用 API 调用文件里面记载的禁用列表,扫描整个项目里面,如果有哪个代码访问了在禁用 API 调用文件记载的禁用方法列表,则给出错误提示
这个需求任务可以强行拆分为两步,第一步是获取到禁用 API 调用文件里面记载的禁用列表,第二步的扫描分析代码调用关系
先不着急创建分析器项目,为了能够让大家更好地理解本演练的内容,这里选择先搭建好一个用于测试的项目,我这里创建名为 NelbecarballReanallyerhohe 的控制台项目,在控制台项目里面存放一个名为 BanList.txt 的文件。这个文件只是一个默认的文本文件,里面存放了一条禁用 API 调用的记载,如以下内容,禁用的是控制台输出的 WriteLine 方法
  1. System.Console.WriteLine
复制代码
其寄义就是如果在当前项目里面,一旦有代码调用了 System.Console.WriteLine 方法,就会给出错误提示
在 Program.cs 里面保持原样的 Console.WriteLine("Hello, World!"); 输出。尝试构建项目,要求给出错误提示,告诉开发者不能调用被禁用的 System.Console.WriteLine 方法,如输出以下错误内容
  1. error Ban01: 不能调用禁用的 API 哦,WriteLine 被 BanList.txt 标记禁用
复制代码
以上就是整个演练的任务需求,这是一个非常经典的分析器任务。也实用于在真实项目里面做 API 约束。比如现在咱正在编写的分析器项目标 EnforceExtendedAnalyzerRules 限制属性,实在现原理也和本章将要介绍的具体技术十分接近。如果大家忘了 EnforceExtendedAnalyzerRules 属性,还请向前翻翻,或参阅 Roslyn 分析器 EnforceExtendedAnalyzerRules 属性的作用
开始编写专用分析器。搭建项目标方式和上文介绍的源代码生成器一样,也如上文所述,源代码生成器和分析器本身就一体的。在一个项目里面同时存在专用分析器和源代码生成器是完全被答应的,也是被推荐的做法。这里就不再详细展开项目标创建方法了,如需整个项目代码,可在本章末尾找到本章所有代码的下载拉取方法
在分析器项目里面创建一个名为 BanAPIAnalyzer 的类型,让其继承自 Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer 类型。如此即可让 BanAPIAnalyzer 成为专用分析器。继承之后,就必要实现 DiagnosticAnalyzer 抽象类型的 SupportedDiagnostics 属性和 Initialize 方法
在专用分析器的计划里面,要求实现 SupportedDiagnostics 属性,告诉框架层当前这个专用分析器类型支持哪些 Diagnostic 内容。一旦 IDE 等配置某些 Diagnostic 被禁用时,如果当前的这个专用分析器的所有 Diagnostic 内容都被禁用,则此专用分析器将不会被启用。另一个作用则是可以在 VisualStudio 的分析器列表里面枚举查看信息,方便配置。比如通过 .editorconfig 文件,将原本是错误品级的 Diagnostic 设置为告诫品级
  1. # 演示在 .editorconfig 文件将原本是 error 等级的 Ban01 设置为 warning 等级
  2. dotnet_diagnostic.Ban01.severity = warning
复制代码
在本演练这里,只添加一个 DiagnosticDescriptor 到 SupportedDiagnostics 属性。如任务需求所述,本演练这里只有一个禁用 API 调用的分析。创建 DiagnosticDescriptor 的方法在上文已经有详细介绍了,上文介绍的是支持多语言的创建方式,相对来说比力繁琐,但也正式。我在这里和大家介绍另一个方式,就是只有单个语言的固定字符串方式,固然了,这样的方式实用范围肯定更小了,难以全球化使用
  1. [DiagnosticAnalyzer(LanguageNames.CSharp)]public class BanAPIAnalyzer : DiagnosticAnalyzer{    ... // 忽略其他代码    public override ImmutableArray SupportedDiagnostics { get; } = new[]    {  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>new DiagnosticDescriptor("Ban01", "CallBanAPI", "不能调用禁用的 API 哦,{0} 被 {1} 标志禁用", category: "Error",  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>    DiagnosticSeverity.Error, isEnabledByDefault: true)    }.ToImmutableArray();}
复制代码
和源代码生成器一样,焦点的代码实现放在 Initialize 方法里面。这两个 Initialize 不同点在于其方法参数上,以下是专用分析器的 Initialize 方法的签名
  1. public override void Initialize(AnalysisContext context)
  2. {
  3.     ... // 忽略其他代码
  4. }
复制代码
通常的专用分析器在 Initialize 的第一句话是调用 AnalysisContext 的 EnableConcurrentExecution 方法。这句话的作用是告诉框架层,当前的专用分析器是线程安全的,可以多线程并发实行。这样可以提高分析器的实行效率,但也要求开发者在编写专用分析器的时候要保证线程安全。不过在调试过程中,却通常将其解释掉,防止多线程进入让调试困难
  1. [DiagnosticAnalyzer(LanguageNames.CSharp)]public class BanAPIAnalyzer : DiagnosticAnalyzer{    public override void Initialize(AnalysisContext context)    {  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>context.EnableConcurrentExecution();  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>... // 忽略其他代码    }    public override ImmutableArray SupportedDiagnostics { get; } = new[]    {  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>new DiagnosticDescriptor("Ban01", "CallBanAPI", "不能调用禁用的 API 哦,{0} 被 {1} 标志禁用", category: "Error",  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>    DiagnosticSeverity.Error, isEnabledByDefault: false)    }.ToImmutableArray();}
复制代码
在 Initialize 的第二句话通常是配置是否对源代码生成器生成的源代码举行分析,默认咱选 None 即可,如以下代码
  1.     public override void Initialize(AnalysisContext context)    {  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>context.EnableConcurrentExecution();  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>... // 忽略其他代码    }
复制代码
这两句话的调用时机没有约束,换句话说就是顺序倒过来也毫无影响
喜欢点点点的伙伴也许看到了在 AnalysisContext 类型里面充满了各种 RegisterXxxAction 的方法。这些方法的作用都是寻找一个注入点,即在什么时机举行分析、在什么范围内举行分析。越是靠后的时机,能够拿到的信息越多,但其分析提示可能就不够实时。具体选用什么时机举行分析,如果把握不准的话,大家可以先选一个比力靠后的时机,调试成功之后再逐渐选择比力靠前的时机。这里的靠前和靠后相对的是构建时机。在本演练里面,为了演示方便,就选用了很是靠后的 RegisterCompilationStartAction 时机,在这里能够拿到完全的 AdditionalFile 附加文件,即 BanList.txt 文件
现在开始这个专用分析器实现的第一步,获取到禁用 API 调用文件里面记载的禁用列表。在咱这个专用分析器里面,比力灵活,答应开发者设置哪个文件记载的就是禁用 API 列表的文件。如在控制台项目(敲黑板,非分析器项目,是那个被分析的项目)里面的 csproj 项目文件通过如下代码指定 BanList.txt 就是记载禁用 API 列表的文件
  1.   <PropertyGroup>
  2.     <BanAPIFileName>BanList.txt</BanAPIFileName>
  3.   </PropertyGroup>
复制代码
一般的分析器项目都在分发的时候带上 $(PackageId).targets 和 $(PackageId).props 文件。但咱这里没有通过 NuGet 举行分发,因此一些可以放在 $(PackageId).targets 和 $(PackageId).props 文件的杂活就必要放入到被分析的项目里面。详细关于如何打包 NuGet 举行分发,我将在下文详细和大家介绍
为什么会提到 $(PackageId).targets 和 $(PackageId).props 文件的杂活呢?这是因为咱在被分析的控制台项目标 csproj 项目文件配置的 BanAPIFileName 属性内容,默认情况下是无法直接被分析器项目感知到的,添加的 BanList.txt 文件也无法被分析器直接感知到。为了让分析器能够拿到配置的 BanAPIFileName 属性,以及 BanList.txt 文件,就必要在被分析的控制台项目标 csproj 项目文件里面添加额外的配置

  • CompilerVisibleProperty : 用于标志有哪些 Property 可以被分析器感知到
  • AdditionalFiles : 添加用于让分析器项目使用的附加文件,官方翻译为 分析器其他文件 或 C# 分析器其他文件
按照以上描述可以了解到,咱必要通过 CompilerVisibleProperty 标志 BanAPIFileName 属性,使用 AdditionalFiles 添加 BanList.txt 文件,即让 BanList.txt 使用 C# 分析器其他文件 生成方式,如下图所示

修改之后的被分析的控制台项目标 csproj 项目文件内容大概如下
  1.   <PropertyGroup>
  2.     <BanAPIFileName>BanList.txt</BanAPIFileName>
  3.   </PropertyGroup><ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>  
复制代码

对于一个通过 NuGet 分发的分析器项目,则是会在 $(PackageId).props 文件里面存放  和  这两个配置,而不必要被分析项目添加这些杂活
以上介绍的 CompilerVisibleProperty 和 AdditionalFiles 是对整个分析器生效,即无论是专用分析器还是源代码生成器,这部分知识内容都完全相同
如对在分析器项目里面读取 PropertyGroup 里面的 Property 感爱好,还请参阅 读取 csproj 项目文件的属性配置方法
完成被分析的控制台项目标 csproj 项目文件配置之后,就可以在 RegisterCompilationStartAction 方法内通过 BanAPIFileName 属性了解到哪个 AdditionalFiles 就是标志禁用列表的文件,其代码如下
  1.     public override void Initialize(AnalysisContext context)    {  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>context.EnableConcurrentExecution();  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>context.RegisterCompilationStartAction((CompilationStartAnalysisContext analysisContext) =>  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>{  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>    if (analysisContext.Options.AnalyzerConfigOptionsProvider.GlobalOptions.TryGetValue(  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>    "build_property.BanAPIFileName", out var fileName))  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>    {  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>... // 忽略其他代码  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>    }  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>});    }
复制代码
再遍历 AdditionalFiles 找到记载禁用 API 列表的文件,代码如下
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>context.RegisterCompilationStartAction(analysisContext =>  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>{  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>    if (analysisContext.Options.AnalyzerConfigOptionsProvider.GlobalOptions.TryGetValue(  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>    "build_property.BanAPIFileName", out var fileName))  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>    {  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>AdditionalText? file = analysisContext.Options.AdditionalFiles.FirstOrDefault(t =>  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>    Path.GetFileName(t.Path) == fileName);  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>if (file != null)  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>{  <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>  <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>    ... // 忽略其他代码  <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>  <ItemGroup>
  36.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  37.   </ItemGroup>}  <ItemGroup>
  38.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  39.   </ItemGroup>    }  <ItemGroup>
  40.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  41.   </ItemGroup>});
复制代码
也许有伙伴表示,这样的实现方法必要两步,第一步是读取 Property 属性,第二步是遍历 AdditionalFiles 文件,相对来说比力麻烦。能否直接在 AdditionalFiles 里面标志配置呢?即如以下的写法
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>
复制代码
这固然是完全可以的啦,只不过其读取方法必要更改一下,按照 Roslyn 分析器 读取 csproj 项目文件的 AdditionalFiles Item 的 Metadata 配置 举行更改。一般情况下不会这么写的,因为在有 NuGet 分发的资助下,将杂活放入到 props 文件里面,整个实际的被分析项目只有编写 BanList.txt 这一句配置,相对来说会比写  更加方便
获取到了配置禁用 API 列表的文件之后,即可通过 AdditionalText.GetText 方法获取到文件内容,代码如下
  1. AdditionalText file = ...;
  2. SourceText sourceText = file.GetText(analysisContext.CancellationToken);
复制代码
这里依然和源代码生成器一样,将令牌传入到调用 AdditionalText.GetText 方法里面,避免读取文件过程中被分析的内容变更导致白白读取内容举行空等
进一步的,直接获取 SourceText 的 Lines 属性,即可拿到一行一个禁用 API 的列表。为了后续判断方便,咱将其转换为哈希集合,合起来的代码如下
  1. var file = analysisContext.Options.AdditionalFiles.FirstOrDefault(t =>    Path.GetFileName(t.Path) == fileName);if (file != null){    ImmutableHashSet banSet =  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>file.GetText()?.Lines.Select(t => t.ToString()).ToImmutableHashSet) ??  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>ImmutableHashSet.Empty;    ... // 忽略其他代码}
复制代码
以上代码就是获取到了禁用 API 列表的文件内容,接下来就是扫描分析代码调用关系,进入到这个专用分析器实现的第二步。这个过程和源代码生成器的分析过程类似,只不过这里不必要生成代码,而是给出分析报告。只是给出分析结果,咱有更多便捷的方法可用,不再和源代码生成器的分析一样逐个爬语法树大概语义树的节点,而是直接使用 RegisterSyntaxNodeAction 方法,给定感爱好的分析内容点
在咱本次演练内容里面,焦点就是判断调用的方法是否在禁用列表里面。即感爱好的分析内容点就是代码里面方法调用,即 SyntaxKind.InvocationExpression 内容。于是在调用 RegisterSyntaxNodeAction 方法过程,将 SyntaxKind.InvocationExpression 作为第二个参数传入,代码如下
  1. ImmutableHashSet<string> banSet =
  2.     file.GetText()?.Lines.Select(t => t.ToString()).ToImmutableHashSet() ??
  3.     ImmutableHashSet<string>.Empty;
  4. analysisContext.RegisterSyntaxNodeAction((SyntaxNodeAnalysisContext nodeAnalysisContext) =>
  5. {
  6.     ... // 忽略其他代码
  7. }, SyntaxKind.InvocationExpression);
复制代码
由于在 RegisterSyntaxNodeAction 参数要求了是 InvocationExpression 类型,在 RegisterSyntaxNodeAction 的委托里面,就可以使用强转方式将 nodeAnalysisContext.Node 转换为 InvocationExpressionSyntax 类型,代码如下
  1. analysisContext.RegisterSyntaxNodeAction(nodeAnalysisContext =>
  2. {
  3.     var invocationExpression = (InvocationExpressionSyntax) nodeAnalysisContext.Node;
  4.     ... // 忽略其他代码
  5. }, SyntaxKind.InvocationExpression);
复制代码
分析调用的 API 离不开语义的辅助,从全语法层面是难以或无法知道具体调用的 API 是哪个的。通过 SemanticModel 获取语义符号,即可知道调用的 API 是哪个
  1. analysisContext.RegisterSyntaxNodeAction(nodeAnalysisContext =>{    var invocationExpression = (InvocationExpressionSyntax) nodeAnalysisContext.Node;    var symbolInfo = nodeAnalysisContext.SemanticModel.GetSymbolInfo(invocationExpression);    if (symbolInfo.Symbol is not IMethodSymbol symbol)    {  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>return;    }    ... // 忽略其他代码}, SyntaxKind.InvocationExpression);
复制代码
理论上这里拿到的 Symbol 必然是 IMethodSymbol 且不是空的
拿到方法符号之后,再获取这个方法所在的类型是哪一个,代码如下
  1. analysisContext.RegisterSyntaxNodeAction(nodeAnalysisContext =>{    var invocationExpression = (InvocationExpressionSyntax) nodeAnalysisContext.Node;    var symbolInfo = nodeAnalysisContext.SemanticModel.GetSymbolInfo(invocationExpression);    if (symbolInfo.Symbol is not IMethodSymbol symbol)    {  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>return;    }    var containingType = symbol.ContainingType;    ... // 忽略其他代码}, SyntaxKind.InvocationExpression);
复制代码
既然已经拿到被调用的方法和被调用的方法所在的类型,那就可以简单使用字符串匹配的方式判断方法是否在禁用列表里面。即先取出其带定名空间的全名,拼接带定名空间的类型名和方法名即可用于判断,代码如下
  1. var containingType = symbol.ContainingType;var symbolDisplayFormat = new SymbolDisplayFormat(    // 带上定名空间和类型名    SymbolDisplayGlobalNamespaceStyle.Omitted,    // 定名空间之前加上 global 防止辩论    SymbolDisplayTypeQualificationStyle  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>.NameAndContainingTypesAndNamespaces);var containingTypeName = containingType.ToDisplayString(symbolDisplayFormat);var name = symbol.Name;var methodName = $"{containingTypeName}.{name}";
复制代码
如此即可拿到方法全名,即 定名空间.类型.方法名 的格式。再进入 banSet 集合判断一下即可了解当前的调用方法是否在禁用了集合中
  1. var methodName = $"{containingTypeName}.{name}";
  2. if (banSet.Contains(methodName))
  3. {
  4.     ... // 当前调用的方法在禁用列表中
  5. }
复制代码
一旦判断当前调用的方法在禁用集合内,则给出错误信息。给出错误信息时,可选列出代码所在的文件、第几行第几列的 Location 信息。从 SyntaxNodeAnalysisContext.Node 创建出 Location 对象,代码如下
  1. var location = Location.Create(nodeAnalysisContext.Node.SyntaxTree, nodeAnalysisContext.Node.FullSpan);
复制代码
再将符号名,即方法名,和记载禁用 API 列表的文件名传入到方法列表里面,用于填充错误详细信息的 "不能调用禁用的 API 哦,{0} 被 {1} 标志禁用" 里面的 {0} 和 {1} 内容,代码如下
  1. nodeAnalysisContext.ReportDiagnostic(Diagnostic.Create(SupportedDiagnostics[0],
  2.     location,
  3.     messageArgs: new object[] { symbol.Name, fileName }));
复制代码
如此即可完成本演练的禁止调用禁用列表的 API 的分析器,整个 BanAPIAnalyzer 类的代码如下,可以看到使用很少的代码量就能实现此功能
  1. [DiagnosticAnalyzer(LanguageNames.CSharp)]public class BanAPIAnalyzer : DiagnosticAnalyzer{    public override void Initialize(AnalysisContext context)    {  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>context.EnableConcurrentExecution();  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>context.RegisterCompilationStartAction(analysisContext =>  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>{  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>    if (analysisContext.Options.AnalyzerConfigOptionsProvider.GlobalOptions.TryGetValue(  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>    "build_property.BanAPIFileName", out var fileName))  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>    {  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>var file = analysisContext.Options.AdditionalFiles.FirstOrDefault(t =>  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>    Path.GetFileName(t.Path) == fileName);  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>  <ItemGroup>
  28.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  29.   </ItemGroup>if (file != null)  <ItemGroup>
  30.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  31.   </ItemGroup>  <ItemGroup>
  32.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  33.   </ItemGroup>{  <ItemGroup>
  34.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  35.   </ItemGroup>  <ItemGroup>
  36.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  37.   </ItemGroup>    ImmutableHashSet banSet =  <ItemGroup>
  38.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  39.   </ItemGroup>  <ItemGroup>
  40.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  41.   </ItemGroup>  <ItemGroup>
  42.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  43.   </ItemGroup>file.GetText()?.Lines.Select(t => t.ToString()).ToImmutableHashSet() ??  <ItemGroup>
  44.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  45.   </ItemGroup>  <ItemGroup>
  46.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  47.   </ItemGroup>  <ItemGroup>
  48.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  49.   </ItemGroup>ImmutableHashSet.Empty;  <ItemGroup>
  50.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  51.   </ItemGroup>  <ItemGroup>
  52.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  53.   </ItemGroup>    analysisContext.RegisterSyntaxNodeAction(nodeAnalysisContext =>  <ItemGroup>
  54.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  55.   </ItemGroup>  <ItemGroup>
  56.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  57.   </ItemGroup>    {  <ItemGroup>
  58.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  59.   </ItemGroup>  <ItemGroup>
  60.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  61.   </ItemGroup>  <ItemGroup>
  62.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  63.   </ItemGroup>var invocationExpression = (InvocationExpressionSyntax) nodeAnalysisContext.Node;  <ItemGroup>
  64.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  65.   </ItemGroup>  <ItemGroup>
  66.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  67.   </ItemGroup>  <ItemGroup>
  68.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  69.   </ItemGroup>var symbolInfo = nodeAnalysisContext.SemanticModel.GetSymbolInfo(invocationExpression);  <ItemGroup>
  70.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  71.   </ItemGroup>  <ItemGroup>
  72.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  73.   </ItemGroup>  <ItemGroup>
  74.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  75.   </ItemGroup>if (symbolInfo.Symbol is not IMethodSymbol symbol)  <ItemGroup>
  76.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  77.   </ItemGroup>  <ItemGroup>
  78.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  79.   </ItemGroup>  <ItemGroup>
  80.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  81.   </ItemGroup>{  <ItemGroup>
  82.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  83.   </ItemGroup>  <ItemGroup>
  84.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  85.   </ItemGroup>  <ItemGroup>
  86.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  87.   </ItemGroup>    return;  <ItemGroup>
  88.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  89.   </ItemGroup>  <ItemGroup>
  90.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  91.   </ItemGroup>  <ItemGroup>
  92.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  93.   </ItemGroup>}  <ItemGroup>
  94.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  95.   </ItemGroup>  <ItemGroup>
  96.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  97.   </ItemGroup>  <ItemGroup>
  98.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  99.   </ItemGroup>var containingType = symbol.ContainingType;  <ItemGroup>
  100.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  101.   </ItemGroup>  <ItemGroup>
  102.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  103.   </ItemGroup>  <ItemGroup>
  104.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  105.   </ItemGroup>var symbolDisplayFormat = new SymbolDisplayFormat  <ItemGroup>
  106.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  107.   </ItemGroup>  <ItemGroup>
  108.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  109.   </ItemGroup>  <ItemGroup>
  110.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  111.   </ItemGroup>(  <ItemGroup>
  112.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  113.   </ItemGroup>  <ItemGroup>
  114.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  115.   </ItemGroup>  <ItemGroup>
  116.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  117.   </ItemGroup>    // 带上定名空间和类型名  <ItemGroup>
  118.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  119.   </ItemGroup>  <ItemGroup>
  120.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  121.   </ItemGroup>  <ItemGroup>
  122.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  123.   </ItemGroup>    SymbolDisplayGlobalNamespaceStyle.Omitted,  <ItemGroup>
  124.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  125.   </ItemGroup>  <ItemGroup>
  126.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  127.   </ItemGroup>  <ItemGroup>
  128.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  129.   </ItemGroup>    // 定名空间之前加上 global 防止辩论  <ItemGroup>
  130.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  131.   </ItemGroup>  <ItemGroup>
  132.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  133.   </ItemGroup>  <ItemGroup>
  134.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  135.   </ItemGroup>    SymbolDisplayTypeQualificationStyle  <ItemGroup>
  136.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  137.   </ItemGroup>  <ItemGroup>
  138.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  139.   </ItemGroup>  <ItemGroup>
  140.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  141.   </ItemGroup>  <ItemGroup>
  142.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  143.   </ItemGroup>.NameAndContainingTypesAndNamespaces  <ItemGroup>
  144.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  145.   </ItemGroup>  <ItemGroup>
  146.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  147.   </ItemGroup>  <ItemGroup>
  148.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  149.   </ItemGroup>);  <ItemGroup>
  150.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  151.   </ItemGroup>  <ItemGroup>
  152.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  153.   </ItemGroup>  <ItemGroup>
  154.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  155.   </ItemGroup>var containingTypeName = containingType.ToDisplayString(symbolDisplayFormat);  <ItemGroup>
  156.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  157.   </ItemGroup>  <ItemGroup>
  158.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  159.   </ItemGroup>  <ItemGroup>
  160.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  161.   </ItemGroup>var name = symbol.Name;  <ItemGroup>
  162.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  163.   </ItemGroup>  <ItemGroup>
  164.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  165.   </ItemGroup>  <ItemGroup>
  166.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  167.   </ItemGroup>var methodName = $"{containingTypeName}.{name}";  <ItemGroup>
  168.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  169.   </ItemGroup>  <ItemGroup>
  170.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  171.   </ItemGroup>  <ItemGroup>
  172.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  173.   </ItemGroup>if (banSet.Contains(methodName))  <ItemGroup>
  174.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  175.   </ItemGroup>  <ItemGroup>
  176.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  177.   </ItemGroup>  <ItemGroup>
  178.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  179.   </ItemGroup>{  <ItemGroup>
  180.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  181.   </ItemGroup>  <ItemGroup>
  182.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  183.   </ItemGroup>  <ItemGroup>
  184.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  185.   </ItemGroup>    var location = Location.Create(nodeAnalysisContext.Node.SyntaxTree, nodeAnalysisContext.Node.FullSpan);  <ItemGroup>
  186.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  187.   </ItemGroup>  <ItemGroup>
  188.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  189.   </ItemGroup>  <ItemGroup>
  190.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  191.   </ItemGroup>    nodeAnalysisContext.ReportDiagnostic(Diagnostic.Create(SupportedDiagnostics[0],  <ItemGroup>
  192.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  193.   </ItemGroup>  <ItemGroup>
  194.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  195.   </ItemGroup>  <ItemGroup>
  196.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  197.   </ItemGroup>  <ItemGroup>
  198.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  199.   </ItemGroup>location,  <ItemGroup>
  200.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  201.   </ItemGroup>  <ItemGroup>
  202.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  203.   </ItemGroup>  <ItemGroup>
  204.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  205.   </ItemGroup>  <ItemGroup>
  206.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  207.   </ItemGroup>messageArgs: new object[] { symbol.Name, fileName }));  <ItemGroup>
  208.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  209.   </ItemGroup>  <ItemGroup>
  210.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  211.   </ItemGroup>  <ItemGroup>
  212.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  213.   </ItemGroup>}  <ItemGroup>
  214.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  215.   </ItemGroup>  <ItemGroup>
  216.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  217.   </ItemGroup>    }, SyntaxKind.InvocationExpression);  <ItemGroup>
  218.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  219.   </ItemGroup>  <ItemGroup>
  220.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  221.   </ItemGroup>}  <ItemGroup>
  222.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  223.   </ItemGroup>    }  <ItemGroup>
  224.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  225.   </ItemGroup>});    }    public override ImmutableArray SupportedDiagnostics { get; } = new[]    {  <ItemGroup>
  226.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  227.   </ItemGroup>new DiagnosticDescriptor("Ban01", "CallBanAPI", "不能调用禁用的 API 哦,{0} 被 {1} 标志禁用", "Error",  <ItemGroup>
  228.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  229.   </ItemGroup>    DiagnosticSeverity.Error, true)    }.ToImmutableArray();}
复制代码
以上代码放在 githubgitee 上,可以使用如下命令行拉取代码。我整个代码堆栈比力庞大,使用以下命令行可以举行部分拉取,拉取速率比力快
先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
  1. git init
  2. git remote add origin https://gitee.com/lindexi/lindexi_gd.git
  3. git pull origin ed27dcda954d4baed58c74b9c1e355468c7135fc
复制代码
以上使用的是国内的 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继承输入以下代码,将 gitee 源换成 github 源举行拉取代码。如果依然拉取不到代码,可以发邮件向我要代码
  1. git remote remove origin
  2. git remote add origin https://github.com/lindexi/lindexi_gd.git
  3. git pull origin ed27dcda954d4baed58c74b9c1e355468c7135fc
复制代码
获取代码之后,进入 Roslyn/NelbecarballReanallyerhohe 文件夹,即可获取到源代码
既然有了分析器,可以给开发者报告出一些告诫或错误信息,那是否还能自动资助开发者修复这些问题呢?这就必要用到高出本文范围的 代码修改器 知识了。编写代码修改器是另外的故事了,这里就不展开了,如果大家对此感爱好,可以参阅 使用 Roslyn 分析代码解释,给 TODO 类型的解释添加负责人、截止日期和 issue 链接跟踪 - walterlv
演练:用源代码生成技术实现中文编程语言

自然而然,大家了解到了从任意的其他非代码文件也能作为输入源,那么是不是可以实现中文编程语言呢?也就是说能否实现从一个包罗中文编程语言的文件里面,读取其内容,根据其内容生成对应的代码,通过此方式实现中文编程语言
开始之前,先给大家看看结果

如果大家感觉这个结果很酷,那请参阅 dotnet 用 SourceGenerator 源代码生成技术实现中文编程语言 文章,里面详细介绍了如何通过源代码生成技术实现中文编程语言
打包 NuGet 包举行分发

学习了很多源代码生成器和分析器的知识,相信此时大家也很想编写和发布一个本身的源代码生成器或分析器。按照 dotnet 里面的惯例,各种产物都会通过 NuGet 的形式举行发布,自然也包括源代码生成器和分析器。接下来我将和大家介绍如何将本身编写的源代码生成器分析器打包成 NuGet 包举行分发
和其他基础库的打包过程非常先进,单独分析器项目本身就可以打出 NuGet 包,只不过必要一些额外的配置。焦点配置如下
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>true  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>false  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>true
复制代码
其中焦点为 IncludeBuildOutput 属性,表示不要将分析器输出程序集放入到 NuGet 包的 lib 文件夹下。一旦被放入到 NuGet 包的 lib 文件夹下,将会让安装了此 NuGet 包的项目引用了分析器程序集,而不会将分析器程序集作为分析器运行
现在如果就直接打出来 NuGet 包,则会看到 NuGet 包是一个空包,什么有用的内容都没有包罗。这是因为分析器项目标输出程序集还没被作为分析器内容打入到 NuGet 包里面。再添加以下代码,将分析器项目标输出程序集放入到 NuGet 包的 analyzers/dotnet/cs 文件夹下,这样就可以让其他项目在安装到本 NuGet 包的时候,按照 NuGet 的约定,从 analyzers/dotnet/cs 文件夹里加载上分析器
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>      
复制代码
大家可以看到,这里使用了 BeforeTargets="_GetPackageFiles" 属性,表示在 NuGet 收集文件之前,将输出的 dll 放入到 NuGet 的 analyzers 文件夹下。为什么不能直接在 Project 下的一级 ItemGroup 里面添加呢?这是因为首次构建之前 $(OutputPath)\$(AssemblyName).dll 是不存在的,直接打包将会输出空包。于是选定在 Build 构建之后,收集文件之前的时机,此最佳时机就是在 _GetPackageFiles 之前
如果选用直接在 Project 下的一级 ItemGroup 里面添加 $(OutputPath)\$(AssemblyName).dll 则不能一次构建出包,此时最推荐的是先做一次 dotnet build 再做一次 dotnet pack --no-build 打包。由于这个命令过程必要拆分为两步,可能会漏掉导致行为不符合预期,因此我在本文里面就特意使用了 Target 的方式举行收集
如果大家对于在 csproj 里面编写 Target 等逻辑不熟悉,还请参阅 如何编写基于 Microsoft.NET.Sdk 的跨平台的 MSBuild Target(附各种自带的 Task) - walterlv
整体修改之后的分析器项目标 csproj 项目文件内容大概如下
  1.       netstandard2.0    latest    true    true    enable    1.0.0  <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>    Copyright (c) lindexi 2020-$([System.DateTime]::Now.ToString(`yyyy`))    MIT    README.md    这里填写描述信息  <ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>true  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>false  <ItemGroup>
  8.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  9.   </ItemGroup>true  <ItemGroup>
  10.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  11.   </ItemGroup>  <ItemGroup>
  12.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  13.   </ItemGroup>  <ItemGroup>
  14.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  15.   </ItemGroup>  <ItemGroup>
  16.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  17.   </ItemGroup>  True      True      Resources.resx  <ItemGroup>
  18.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  19.   </ItemGroup>  <ItemGroup>
  20.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  21.   </ItemGroup>  ResXFileCodeGenerator      Resources.Designer.cs  <ItemGroup>
  22.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  23.   </ItemGroup>  <ItemGroup>
  24.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  25.   </ItemGroup>  <ItemGroup>
  26.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  27.   </ItemGroup>   
复制代码
第一个 PropertyGroup 块为分析器固有信息,其中的 1.0.0 版本号被程序集和 NuGet 包版本号所共用。如果只为指定 NuGet 的包版本号而不影响程序集的版本号,可使用专用的 PackageVersion 属性

第二个 PropertyGroup 块为 NuGet 包的信息。其中的 这里填写描述信息 为 NuGet 包的描述信息,这个描述信息可以在 NuGet Package Explorer 里面直接看到,如下图所示,直接使用 NuGet Package Explorer 打开 NuGet 包,即可看到描述信息

而 ReadMe 文件记载则是必要与下方的  配合才能完成,用于放入辨认的 README.md 文件,资助开发者入门使用此分析器 NuGet 包
版权 Copyright 信息里面,我使用了 $([System.DateTime]::Now.ToString(yyyy)) 语法,用于获取当前年份。这样可以保证每年都会更新版权信息,不必要手动修改,只必要在新年的时候重新打包即可
再往下是 SuppressDependenciesWhenPacking 配置无依靠和 IncludeBuildOutput 配置不要将输出文件放入到 nuget 的 lib 文件夹等信息,这部分上文有描述,这里就不再赘述
以上内容里面用到了很多 NuGet 打包相关属性,如对此感爱好,还请参阅 dotnet 打包 NuGet 的配置属性大全整理
如果大家打不出来精确的 NuGet 包,可以拉取我的代码举行对比参考
本章以上的代码放在 githubgitee 上,可以使用如下命令行拉取代码。我整个代码堆栈比力庞大,使用以下命令行可以举行部分拉取,拉取速率比力快
先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
  1. git init
  2. git remote add origin https://gitee.com/lindexi/lindexi_gd.git
  3. git pull origin 7ee17551c750a643593f6f5e4a0d03f89456b393
复制代码
以上使用的是国内的 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继承输入以下代码,将 gitee 源换成 github 源举行拉取代码。如果依然拉取不到代码,可以发邮件向我要代码
  1. git remote remove origin
  2. git remote add origin https://github.com/lindexi/lindexi_gd.git
  3. git pull origin 7ee17551c750a643593f6f5e4a0d03f89456b393
复制代码
获取代码之后,进入 Roslyn/NayijainawNerkanekajawi 文件夹,即可获取到源代码
以上是十分简单地将分析器打成 NuGet 包。如编写一个 禁用API调用 的分析器演练章节中所述,在制作 NuGet 包的过程可以附带 props 文件和 targets 文件,用于在安装 NuGet 包的时候,自动添加一些配置。这样就可以让分析器的使用更加方便,不必要安装了分析器的项目手动添加配置
回顾一下原本在 禁用API调用 的分析器章节中的引用分析器的 NelbecarballReanallyerhohe 控制台项目标 csproj 文件内容
  1.   <PropertyGroup>
  2.     <BanAPIFileName>BanList.txt</BanAPIFileName>
  3.   </PropertyGroup><ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>  
复制代码
以上内容里面的  和  都是固定配置内容。完全可以放入到分析器 NuGet 包里面,不必要每个安装了分析器的项目都手动添加这些重复的配置内容
在分析器的 NuGet 包里面存放 props 文件和 targets 文件,将分析器所需配置放入到这两个文件里面,即可在安装完 NuGet 包之后,应用这两个文件里面的配置,避免安装分析器的项目必要添加固定配置内容
依然是为了方便大家获取源代码,我这里重新拷贝 禁用API调用 的分析器演练章节的项目里面的代码,重新新建了名为 JabeehuharKekajerlurlaw.Analyzer 的分析器项目和名为 JabeehuharKekajerlurlaw 控制台项目
起首在分析器项目里面新建一个名为 Assets 的文件夹。这个 Assets 文件夹名仅仅只是我的喜欢,大家可以根据本身的喜欢换成其他的文件夹名。再在 Assets 文件夹里面新建两个文件,分别是 Package.props 和 Package.targets 文件。这两个文件的内容如下
Package.props 文件内容如下
  1. [/code]Package.targets 文件内容如下
  2. [code]  <ItemGroup>
  3.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  4.   </ItemGroup>  <ItemGroup>
  5.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  6.   </ItemGroup>
复制代码

针对上文的 禁用API调用 的分析器演练的需求,完全将配置的信息写入到 Package.targets 文件里面,确保顺序足够靠后,在对应的安装了分析器的项目里面完成配置之后,再设置加入到 AdditionalFiles 文件里面
完成 Package.props 和 Package.targets 文件的创建之后,将这两个文件按照 Roslyn 打包自界说的文件到 NuGet 包 博客的方法,将这两个文件打包到 NuGet 包的 build 文件夹下
  1.   <ItemGroup>
  2.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  3.   </ItemGroup>   
复制代码
放入到 NuGet 包里面的 build 文件夹下,这样安装了分析器的项目就会自动引入这两个文件,依靠这两个文件提供的配置,不必要手动添加配置。以下是从原本项目引用方式分析器,更改为引用分析器 NuGet 包的方式之后,控制台项目标 csproj 文件里的配置内容发生的变更
原来的引用分析器项目:
  1.   <PropertyGroup>
  2.     <BanAPIFileName>BanList.txt</BanAPIFileName>
  3.   </PropertyGroup><ItemGroup>
  4.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  5.   </ItemGroup>  <ItemGroup>
  6.     <ProjectReference Include="..\ChunecilarkenaLibeewhemke\ChunecilarkenaLibeewhemke.csproj" ReferenceOutputAssembly="true" OutputItemType="Analyzer" />
  7.   </ItemGroup>  
复制代码
改用分析器 NuGet 包之后:
  1.   <PropertyGroup>
  2.     <BanAPIFileName>BanList.txt</BanAPIFileName>
  3.   </PropertyGroup>
复制代码
可以看到,引用分析器 NuGet 包之后,不必要再手动添加  和  这两个配置内容,这两个配置内容已经被分析器 NuGet 包的 Package.targets 文件提供了。整个项目看起来更加简便
以上在分析器 NuGet 包里面存放 props 和 targets 的全部项目代码放在 githubgitee 上,可以使用如下命令行拉取代码。我整个代码堆栈比力庞大,使用以下命令行可以举行部分拉取,拉取速率比力快
先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
  1. git init
  2. git remote add origin https://gitee.com/lindexi/lindexi_gd.git
  3. git pull origin fb40665eacad9578d14bf799969bb0e9ac6f0b89
复制代码
以上使用的是国内的 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继承输入以下代码,将 gitee 源换成 github 源举行拉取代码。如果依然拉取不到代码,可以发邮件向我要代码
  1. git remote remove origin
  2. git remote add origin https://github.com/lindexi/lindexi_gd.git
  3. git pull origin fb40665eacad9578d14bf799969bb0e9ac6f0b89
复制代码
获取代码之后,进入 Roslyn/JabeehuharKekajerlurlaw 文件夹,即可获取到源代码
以上就是 dotnet 的源代码生成器、分析器的入门介绍,盼望能够资助大家更好的了解源代码生成器、分析器的使用方法。在使用过程中,可能以上介绍的内容还不够满足大家的需求。我将在下文给出一些常用方法,供大家参考
常用方法

以下是我记载的一些零碎的常用方法和做法,供大家参考,盼望能够办理大家一些使用上的问题
获取配置

IIncrementalGenerator 增量 Source Generator 生成代码入门 读取 csproj 项目文件的属性配置
Roslyn 分析器 读取 csproj 项目文件的 AdditionalFiles Item 的 Metadata 配置
获取文件的实际当地路径

Roslyn 源代码生成器 SourceGenerator 获取代码文件的当地绝对路径
获取引用程序集的所有类型

IIncrementalGenerator 增量 Source Generator 生成代码入门 获取引用程序集的所有类型
判断程序集之间的 InternalsVisibleTo 关系

IIncrementalGenerator 增量 Source Generator 生成代码入门 判断程序集之间的 InternalsVisibleTo 关系
判断程序集的引用关系

IIncrementalGenerator 增量 Source Generator 生成代码入门 判断程序集的引用关系
获取项目默认定名空间

IIncrementalGenerator 增量 Source Generator 生成代码入门 获取项目默认定名空间
参考文档

从零开始学习 dotnet 编译过程和 Roslyn 源码分析 - walterlv
手把手教你写 Roslyn 修改编译
Source Generators Cookbook
Source Generators
Incremental Generators
更多编译器、代码分析、代码生成相关博客,请参阅我的 博客导航

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

张春

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表