在C# IIncrementalGenerator源码生成中获取Attribute属性值
解决源代码生成器中获取自定义Attribute属性值的问题
核心思路
你当前的代码仅传递了类的语法节点到Execute方法,未携带Attribute的参数值。需要在语法解析阶段就提取出Attribute构造函数的参数(即Aggregate的值),并和类节点一起传递到后续生成逻辑中。
具体实现步骤
1. 定义数据承载类
创建一个记录类,统一保存需要的类节点和属性值信息:
public record EventApplyInfo(ClassDeclarationSyntax ClassDeclaration, string AggregateName);
2. 修改属性解析逻辑
调整GetSemanticTargetForGeneration方法,不再返回ClassDeclarationSyntax,而是解析Attribute的构造函数参数,返回封装好的EventApplyInfo:
private static EventApplyInfo? GetSemanticTargetForGeneration(GeneratorAttributeSyntaxContext context, CancellationToken ct) { var attributeData = context.Attributes.First(); string fullName = attributeData.AttributeClass.ToDisplayString(); if (fullName == EventApplyAttribute) { if (context.TargetNode is not ClassDeclarationSyntax classDeclaration) return null; // 解析构造函数第一个参数(对应Aggregate属性) if (attributeData.ConstructorArguments.FirstOrDefault().Value is string aggregateName) { return new EventApplyInfo(classDeclaration, aggregateName); } } return null; }
3. 调整增量生成器的类型映射
修改Initialize方法中的增量提供者类型,从ClassDeclarationSyntax改为EventApplyInfo:
public void Initialize(IncrementalGeneratorInitializationContext context) { IncrementalValuesProvider<EventApplyInfo?> eventApplyInfos = context.SyntaxProvider .ForAttributeWithMetadataName( EventApplyAttribute, predicate: (node, _) => node is ClassDeclarationSyntax, transform: (ctx, ct) => GetSemanticTargetForGeneration(ctx, ct)) .Where(static m => m is not null); IncrementalValueProvider<(Compilation, ImmutableArray<EventApplyInfo>)> compilationAndInfos = context.CompilationProvider.Combine(eventApplyInfos.Collect() .Select(static infos => infos.Where(info => info != null).ToImmutableArray()!)); context.RegisterSourceOutput(compilationAndInfos, static (spc, source) => Execute(source.Item1, source.Item2, spc)); }
4. 在Execute中使用属性值
修改Execute方法参数,直接获取每个类对应的AggregateName:
private static void Execute(Compilation compilation, ImmutableArray<EventApplyInfo> eventApplyInfos, SourceProductionContext context) { foreach (var info in eventApplyInfos) { // 拿到示例中的"BaseClass"值和对应的类节点 string aggregateName = info.AggregateName; ClassDeclarationSyntax classDecl = info.ClassDeclaration; // 后续生成代码逻辑示例:输出调试信息 context.ReportDiagnostic(Diagnostic.Create( new DiagnosticDescriptor("TEST001", "Aggregate Info", "Class {0} applies to aggregate {1}", "SourceGen", DiagnosticSeverity.Info, true), classDecl.GetLocation(), classDecl.Identifier.Text, aggregateName)); } }
补充说明
如果你的Attribute是通过命名参数设置属性(比如[EventApply(Aggregate = "BaseClass")]),则需要通过AttributeData.NamedArguments解析,对应代码:
var aggregateArg = attributeData.NamedArguments.FirstOrDefault(arg => arg.Key == nameof(EventApplyAttribute.Aggregate)); if (aggregateArg.Value.Value is string aggregateName) { // 使用解析得到的aggregateName }
内容的提问来源于stack exchange,提问作者Dani
相关产品推荐
相关产品推荐

