前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Roslyn 分析器 读取 csproj 项目文件的 AdditionalFiles Item 的 Metadata 配置

Roslyn 分析器 读取 csproj 项目文件的 AdditionalFiles Item 的 Metadata 配置

作者头像
林德熙
发布2024-10-12 12:05:36
1000
发布2024-10-12 12:05:36
举报
文章被收录于专栏:林德熙的博客

定义在 ItemGroup 里面的各个引用文件的 Item 可带上自定义的 Metadata 内容,这部分内容需要转换到 AdditionalFiles 的 Metadata 上才能被分析器所获取

上一篇博客告诉大家如何在 IIncrementalGenerator 增量 Source Generator 里读取 csproj 项目文件的属性配置,详细请看: IIncrementalGenerator 增量 Source Generator 生成代码入门 读取 csproj 项目文件的属性配置

在上一篇博客里面,核心是通过配置了 CompilerVisibleProperty 让属性可见,如下面代码所示

代码语言:javascript
复制
  <PropertyGroup>
    <MyCustomProperty>lindexi is doubi</MyCustomProperty>
  </PropertyGroup>

  <ItemGroup>
    <CompilerVisibleProperty Include="MyCustomProperty" />
  </ItemGroup>

在分析器里面获取属性内容的核心代码如下

代码语言:javascript
复制
            context.RegisterImplementationSourceOutput(context.AnalyzerConfigOptionsProvider,
                (productionContext, provider) =>
                {
                    var text = string.Empty;

                    // 通过 csproj 等 PropertyGroup 里面获取
                    // 需要将可见的,放入到 CompilerVisibleProperty 里面
                    // 需要加上 `build_property.` 前缀
                    if (provider.GlobalOptions.TryGetValue("build_property.MyCustomProperty", out var myCustomProperty))
                    {
                        text += " " + myCustomProperty;
                    }
                });

本文将告诉大家如何获取引用文件的 ItemGroup 里面的 Item 的 Metadata 内容如何获取到。如下面项目文件的代码,定义了名为 PaintStateDiagramMarkdownFile 的 Item 项,此项里面包含了 Link 这个 Metadata 内容

代码语言:javascript
复制
  <ItemGroup>
    <PaintStateDiagramMarkdownFile Include="..\KereqeewahaihibayNohelqiji\*.txt" Link="Assets\StateDiagrams\%(RecursiveDir)%(Filename)%(Extension)" />
  </ItemGroup>

如期望让其 PaintStateDiagramMarkdownFile 项在分析器可见,需要将其添加到 AdditionalFiles 里面,如下面代码

代码语言:javascript
复制
  <ItemGroup>
    <AdditionalFiles Include="@(PaintStateDiagramMarkdownFile)"/>
  </ItemGroup>

为了让 Link 这个 Metadata 内容同样被分析器可见,需要在将 PaintStateDiagramMarkdownFile 添加到 AdditionalFiles 时,附带将 Link 带上,更新之后的代码如下

代码语言:javascript
复制
  <ItemGroup>
    <AdditionalFiles Include="@(PaintStateDiagramMarkdownFile)" Link="%(Link)"/>
  </ItemGroup>

再使用 CompilerVisibleItemMetadata 设置 AdditionalFiles 的 Link 也是对分析器可见,代码如下

代码语言:javascript
复制
  <ItemGroup>
    <CompilerVisibleItemMetadata Include="AdditionalFiles" MetadataName="Link" />
  </ItemGroup>

如此即可在后续分析器里面里面使用 AnalyzerConfigOptionsProvider 的 GetOptions 方法获取到 Metadata 信息

以上编辑之后的 csproj 项目文件内容如下

代码语言:javascript
复制
  <ItemGroup>
    <PaintStateDiagramMarkdownFile Include="..\KereqeewahaihibayNohelqiji\*.txt" Link="Assets\StateDiagrams\%(RecursiveDir)%(Filename)%(Extension)" />

    <AdditionalFiles Include="@(PaintStateDiagramMarkdownFile)" Link="%(Link)"/>

    <CompilerVisibleItemMetadata Include="AdditionalFiles" MetadataName="Link" />
  </ItemGroup>

当然了,在真正的 NuGet 打包项目上,常常会将 AdditionalFiles 和 CompilerVisibleItemMetadata 写到 target 或 props 文件里面,而不是放在 csproj 里面。详细请参阅我的 博客导航 获取分析器入门知识

在分析器里面里面,可先收集或用其他方式获取到 AdditionalFiles 内容,将其传入给到 AnalyzerConfigOptionsProvider 的 GetOptions 方法,即可获取到 AnalyzerConfigOptions 对象。再对 AnalyzerConfigOptions 调用 TryGetValue 方法,传入字符串格式是 build_metadata.AdditionalFiles.[MetadataName] 即可获取到 Metadata 信息。以上字符串格式的 [MetadataName] 还请替换为实际需要获取的值,如本文以上例子里面期望获取到 Link 这个 Metadata 内容,可使用如下代码

代码语言:javascript
复制
AnalyzerConfigOptionsProvider analyzerConfigOptionsProvider = ...
AdditionalText additionalText = ...

                        AnalyzerConfigOptions analyzerConfigOptions = analyzerConfigOptionsProvider.GetOptions(additionalText);
                        if (analyzerConfigOptions.TryGetValue("build_metadata.AdditionalFiles.Link", out var link))
                        {
                            
                        }

为了更好的说明使用方法,我创建了两个项目,其中一个项目是分析器项目,另一个是控制台项目。我将演示如何获取控制台项目所配置的 PaintStateDiagramMarkdownFile 项的 Link 信息。本文内容里面只给出关键代码片段,如需要全部的项目文件,可到本文末尾找到本文所有代码的下载方法

以下是控制台项目 CujelcijallChearjawjuja 的 csproj 文件的代码

代码语言:javascript
复制
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PaintStateDiagramMarkdownFile Include="..\KereqeewahaihibayNohelqiji\*.txt" Link="Assets\StateDiagrams\%(RecursiveDir)%(Filename)%(Extension)" />
    <None Include="@(PaintStateDiagramMarkdownFile)"></None>
    <AdditionalFiles Include="@(PaintStateDiagramMarkdownFile)" Link="%(Link)"/>

    <CompilerVisibleItemMetadata Include="AdditionalFiles" MetadataName="Link" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\KereqeewahaihibayNohelqiji\KereqeewahaihibayNohelqiji.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
  </ItemGroup>

</Project>

可以看到写了 PaintStateDiagramMarkdownFile 项,且将其添加到 AdditionalFiles 里面,添加的过程中还将 PaintStateDiagramMarkdownFile 的 Link 赋值给到 AdditionalFiles 的 Link 里

最后配置 CompilerVisibleItemMetadata 让 AdditionalFiles 的 Link 信息被分析器可见

中间添加的 <None Include="@(PaintStateDiagramMarkdownFile)"></None> 只是一个简单的调试代码,用于让我可以在 VisualStudio 项目里面看到文件而已,和本文实际的演示没有关系

添加分析器 KereqeewahaihibayNohelqiji 项目,分析器项目的 csproj 项目文件的代码如下

代码语言:javascript
复制
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" PrivateAssets="all" />
    <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.10.0" PrivateAssets="all" />
  </ItemGroup>

</Project>

以上代码的 EnforceExtendedAnalyzerRules 属性含义请参阅 Roslyn 分析器 EnforceExtendedAnalyzerRules 属性的作用

在 KereqeewahaihibayNohelqiji 项目放入 TextFile.txt 文件用于给 CujelcijallChearjawjuja 项目引用

在 KereqeewahaihibayNohelqiji 编写名为 YelgahainaljinalBehoballdewur 的 IIncrementalGenerator 增量 Source Generator 生成器,代码如下

代码语言:javascript
复制
namespace KereqeewahaihibayNohelqiji
{
    [Generator(LanguageNames.CSharp)]
    internal class YelgahainaljinalBehoballdewur : IIncrementalGenerator
    {
        public void Initialize(IncrementalGeneratorInitializationContext context)
        {
            // 在这里编写代码
            context.RegisterImplementationSourceOutput(context.AdditionalTextsProvider.Collect().Combine(context.AnalyzerConfigOptionsProvider),
                (productionContext, provider) =>
                {
                    // 这里的代码只有当配置初始化或变更时才会被执行
                    var additionalTextArray = provider.Left;
                    AnalyzerConfigOptionsProvider analyzerConfigOptionsProvider = provider.Right;

                    var stringBuilder = new StringBuilder();
                    for (int i = 0; i < 3; i++)
                    {
                        stringBuilder.Append('"');
                    }
                    stringBuilder.AppendLine();

                    foreach (AdditionalText additionalText in additionalTextArray)
                    {
                        AnalyzerConfigOptions analyzerConfigOptions = analyzerConfigOptionsProvider.GetOptions(additionalText);
                        if (analyzerConfigOptions.TryGetValue("build_metadata.AdditionalFiles.Link", out var link))
                        {
                            stringBuilder.AppendLine($"File={additionalText.Path}");
                            stringBuilder.AppendLine($"Link={link}");
                        }
                    }

                    for (int i = 0; i < 3; i++)
                    {
                        stringBuilder.Append('"');
                    }

                    var code = @"using System;
namespace CujelcijallChearjawjuja
{
    public static class Foo
    {
        public static void F1()
        {
            Console.WriteLine(" + stringBuilder.ToString() + @");
        }
    }
}";
                    productionContext.AddSource("Foo.cs", code);
                });
        }
    }
}

如此期望能够将控制台项目里面的 PaintStateDiagramMarkdownFile 作为 Foo 类型的 F1 方法输出控制台信息的内容

编辑控制台项目 CujelcijallChearjawjuja 的 Program.cs 文件,添加如下代码

代码语言:javascript
复制
using CujelcijallChearjawjuja;

Foo.F1();

运行控制台项目,大概可以看到如下输出内容。如此可以证明此方法可以获取 Item 项里面配置的 Metadata 信息

代码语言:javascript
复制
File=C:\lindexi\Workbench\CujelcijallChearjawjuja\..\KereqeewahaihibayNohelqiji\TextFile.txt
Link=Assets\StateDiagrams\TextFile.txt

本文代码放在 githubgitee 上,可以使用如下命令行拉取代码。我整个代码仓库比较庞大,使用以下命令行可以进行部分拉取,拉取速度比较快

先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码

代码语言:javascript
复制
git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin eb119d9e64e387cea847aee79f4509744c349018

以上使用的是国内的 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码,将 gitee 源换成 github 源进行拉取代码。如果依然拉取不到代码,可以发邮件向我要代码

代码语言:javascript
复制
git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin eb119d9e64e387cea847aee79f4509744c349018

获取代码之后,进入 Workbench/CujelcijallChearjawjuja 文件夹,即可获取到源代码

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档