嗨,我正在尝试编写一个使用
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
我知道这个问题有点陈旧,但由于它仍然在谷歌上经常出现,我想展示我当前的解决方案,它结合了评论中给出的提示。
据我所知,添加这样的依赖项在通过 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
文件位于正确的目录中。