我正在使用增量生成器方法编写源生成器。
我想让开发人员能够有条件地生成一些额外的代码(例如,额外的注释、调试打印输出、生成的代码中的迂腐验证等(,我希望这由以下任意一种控制:
DefineConstants
,使用我的源生成器将以下内容添加到项目的.csproj
文件中:
<PropertyGroup>
<DefineConstants>$(DefineConstants);MY_PROJECT_EXTRA</DefineConstants>
</PropertyGroup>
- 或通过
dotnet build
命令行上的-p:
选项:
dotnet build ProjectUsingMySourceGeneratorCode.csproj -p:MyProjectExtra=true
我检查了我可以访问的以下类型:IncrementalGeneratorInitializationContext
、SourceProductionContext
、Compilation
,但找不到任何内容。
作为解决方法,我可以添加一个自定义属性,开发人员可以使用该属性来装饰他们想要控制的语法元素,但这可能需要开发人员手动添加许多类/方法的属性。
有没有一种方法可以访问IncrementalGenerator
工作流中的DefineConstants
或命令行-p:
属性(或任何其他编译时设置(?
感谢@caton7的评论,我找到了一种使用.editorconfig
的初始解决方案。我认为增量生成器的工作方式可能与原始源生成器略有不同,所以我最终做了类似于https://github.com/dotnet/roslyn/blob/main/docs/features/source-generators.cookbook.md#access-分析器配置属性。
我的解决方案
.editorconfig
myvalue = foo
SourceGenerator.cs
public class SourceGenerator : IIncrementalGenerator {
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// Step 1. Identify the classes.
var classDeclarations = context.SyntaxProvider.CreateSyntaxProvider(
static (node, ct) => true /* Update with your code */,
static (context, ct) => context.Node as ClassDeclarationSyntax /* Update with your code*/)
.Where(CommonExtensions.IsNotNull);
// Step 2. Combine analyser, compilation and class declaration
var analizerConfigOptionsCompilationAndClasses = context
.AnalyzerConfigOptionsProvider
.Combine(context
.CompilationProvider
.Combine(classDeclarations.Collect()));
// Step 3. Register the source output to generate the code.
context.RegisterSourceOutput(
analizerConfigOptionsCompilationAndClasses,
static (context, settings) => Execute(context, settings.Left, settings.Right.Left, settings.Right.Right));
}
private static Execute(SourceProductionContext context, AnalyzerConfigOptionsProvider analyzerConfigOptionsProvider, Compilation compilation, ImmutableArray<ClassDeclarationSyntax?> classDeclarationSyntaxes))
{
// NOTE: Unsure why by analyzerConfigOptionsProvider.TryGetValue("myvalue", out var x) would never return the values I would be expecting.
foreach (var classDeclarationSyntax in classDeclarationSyntaxes)
{
if (classDeclarationSyntax is null)
{
continue;
}
var options = analyzerConfigOptionsProvider.GetOptions(classDeclarationSyntax.SyntaxTree);
options.TryGetValue("myvalue", out string? myvalue);
/* myvalue should now be equal to the string foo as defined in .editorconfig */
}
}
}