在同一解决方案中使用带有依赖项的 SourceGenerator

问题描述 投票:0回答:1

嗨,我正在尝试编写一个使用

SourceGenerator
包的
Humanizer
(此包仅在生成代码时需要,不应在使用 SourceGenerator 的项目中添加为参考)

所以我有以下文件:

TestSourceGenerator\TestSourceGenerator.csproj

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFramework>netstandard2.0</TargetFramework>
        <LangVersion>latest</LangVersion>
        <Nullable>enable</Nullable>
        <IncludeBuildOutput>false</IncludeBuildOutput>
        <IsRoslynComponent>true</IsRoslynComponent>
        <ImplicitUsings>enable</ImplicitUsings>
        <TargetsForTfmSpecificContentInPackage>$(TargetsForTfmSpecificContentInPackage);_AddAnalyzersToOutput</TargetsForTfmSpecificContentInPackage>
        <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
    </PropertyGroup>
    
    <ItemGroup>
        <PackageReference Include="Humanizer.Core" Version="2.14.1" PrivateAssets="all" GeneratePathProperty="true" />
        <PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.1.0" PrivateAssets="all" />
        <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.1.0" PrivateAssets="all" />
        <PackageReference Include="Microsoft.CSharp" Version="4.7.0" PrivateAssets="all" />
    </ItemGroup>

    <Target Name="_AddAnalyzersToOutput">
        <ItemGroup>
            <TfmSpecificPackageFile Include="$(OutputPath)\$(AssemblyName).dll" PackagePath="analyzers/dotnet/cs" Pack="true" Visible="false" />
            <TfmSpecificPackageFile Include="$(OutputPath)\Humanizer.dll" PackagePath="analyzers/dotnet/cs" Pack="true" Visible="false" />
        </ItemGroup>
    </Target>

</Project>

TestSourceGenerator\SourceGenerator.cs

using System.Text;
using Humanizer;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;

namespace TestSourceGenerator;

[Generator]
public class SourceGenerator : ISourceGenerator
{
    public void Execute(GeneratorExecutionContext context)
    {

        var builder = new StringBuilder(1024);

        builder.AppendLine(@$"using System;
namespace {context.Compilation.Assembly.ContainingNamespace?.Name ?? context.Compilation.Assembly.Name};
static class AssemblyInformation {{
    public static string Name = ""{context.Compilation.AssemblyName}"";
    public static string HumanizedName = ""{context.Compilation.AssemblyName.Humanize()}"";
}}
");

        context.AddSource("AssemblyInformation.cs", SourceText.From(builder.ToString(), Encoding.UTF8));
    }

    public void Initialize(GeneratorInitializationContext context)
    {

    }
}

TestSourceGenerator\Properties\launchSettings.json

{
  "profiles": {
    "Profile 1": {
      "commandName": "DebugRoslynComponent",
      "targetProject": "..\\ConsoleApp1\\ConsoleApp1.csproj"
    }
  }
}

ConsoleApp1\ConsoleApp1.csproj

<Project Sdk="Microsoft.NET.Sdk">

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

  <ItemGroup>
    <ProjectReference Include="..\TestSourceGenerator\TestSourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="true"  />
  </ItemGroup>

</Project>

ConsoleApp1\Program.cs

Console.WriteLine("Name: " + AssemblyInformation.Name);
Console.WriteLine("Name: " + AssemblyInformation.HumanizedName);

当我使用

Profile 1
调试 SourceGenerator 时,一切都按预期工作。 但如果我尝试编译
ConsoleApp1
,它会抱怨找不到
Humanizer
,即使它在那里

Generator 'SourceGenerator' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type 'FileNotFoundException' with message 'Could not load file or assembly 'Humanizer, Version=2.14.0.0, Culture=neutral, PublicKeyToken=979442b78dfc278e' or one of its dependencies. The system cannot find the file specified.'

我错过了什么? 当我打包 SourceGenerator 时,我已验证 Humanizer 是 nuget 文件的一部分。

可以在此处找到代码副本:https://github.com/AnderssonPeter/TestSourceGenerator

c# roslyn sourcegenerators csharp-source-generator
1个回答
0
投票

我知道这个问题有点陈旧,但由于它仍然在谷歌上经常出现,我想展示我当前的解决方案,它结合了评论中给出的提示。

据我所知,添加这样的依赖项在通过 Nuget 包引用同一解决方案中的生成器时都有效,尽管我还没有广泛测试该场景。

我的生成器的

.csproj
取决于
Tomlyn
库 /
Tomlyn.dll
我已经像这样添加了它:

    <!-- Generation time dependencies need special treatment 
        see: https://github.com/dotnet/roslyn/blob/main/docs/features/source-generators.cookbook.md#use-functionality-from-nuget-packages
        and: https://github.com/dotnet/roslyn-sdk/blob/main/samples/CSharp/SourceGenerators/SourceGeneratorSamples/CSharpSourceGeneratorSamples.csproj
    -->
    <ItemGroup>
        <PackageReference Include="Tomlyn" Version="0.17.0" GeneratePathProperty="true" PrivateAssets="all" />
        <None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />      
        <None Include="$(PKGTomlyn)\lib\netstandard2.0\*.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
    </ItemGroup>

    
    <PropertyGroup>
        <GetTargetPathDependsOn>$(GetTargetPathDependsOn);GetDependencyTargetPaths</GetTargetPathDependsOn>
    </PropertyGroup>

    <Target Name="GetDependencyTargetPaths">
        <ItemGroup>                     
            <TargetPathWithTargetPlatformMoniker Include="$(PKGTomlyn)\lib\netstandard2.0\Tomlyn.dll" IncludeRuntimeDependency="false" />
        </ItemGroup>
    </Target>

注意

GeneratePathProperty="true"
上的
PrivateAssets="all"
PackageReference

项目组中的两个

None
来自建议 here,仅当将生成器打包为 Nuget 包时,该依赖项才应在生成期间可用。而第二个
PropertyGroup
Target
应使用 here 中的示例来确保在同一解决方案中使用生成器时
Tomlyn.dll
文件位于正确的目录中。

© www.soinside.com 2019 - 2024. All rights reserved.