提问人:Dani 提问时间:10/2/2023 最后编辑:Dani 更新时间:10/10/2023 访问量:132
在 C# 源代码生成中获取属性属性值 - IIncrementalGenerator
Get attribute property value in C# source generation - IIncrementalGenerator
问:
我有以下属性:
[AttributeUsage(AttributeTargets.Class)]
public class EventApplyAttribute : Attribute
{
public string Aggregate { get; }
public EventApplyAttribute(string aggregate)
{
Aggregate = aggregate;
}
}
我像这样使用属性:
[EventApplyAttribute(nameof(BaseClass))]
public class Test : BaseEvent{}
我使用这个源生成器:
[Generator]
public class SourceGeneration : IIncrementalGenerator
{
private const string EventApplyAttribute = "DomainLibrary.EventApplyAttribute";
public void Initialize(IncrementalGeneratorInitializationContext context)
{
IncrementalValuesProvider<ClassDeclarationSyntax> classDeclarations = 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<ClassDeclarationSyntax>)> compilationAndClasses
= context.CompilationProvider.Combine(classDeclarations.Collect());
context.RegisterSourceOutput(compilationAndClasses,
static (spc, source) => Execute(source.Item1, source.Item2, spc));
}
private static void Execute(Compilation compilation, ImmutableArray<ClassDeclarationSyntax> classes, SourceProductionContext context)
{
}
private static ClassDeclarationSyntax? GetSemanticTargetForGeneration(GeneratorAttributeSyntaxContext context, CancellationToken ct)
{
string fullName = context.Attributes.First().AttributeClass.ToDisplayString();
if (fullName == EventApplyAttribute)
{
if (context.TargetNode is not ClassDeclarationSyntax classDeclaration)
return null;
return classDeclaration;
}
return null;
}
}
Execute 方法中的 classes 数组具有预期的类。如果我遍历数组,我会得到很多信息。有没有办法同时访问属性属性值。在这种情况下,它会是“BaseClass”吗?我什么都找不到...
答:
0赞
Youssef13
10/2/2023
#1
该类型具有可以访问的属性。每个属性都有一个属性,其中包含您想要的内容。应在 transform 方法中将此信息提取到值相等模型中。GeneratorAttributeSyntaxContext
Attributes
ConstructorArguments
1赞
V0ldek
10/2/2023
#2
可以使用 AttributeList
属性从对象中提取属性,该属性包含属性列表的语法。但这是乏味的,而且非常低级。ClassDeclarationSyntax
为了使它更容易并使生成器更有效率,您应该按照@Youssef13所说的去做,并将值转换为 。已经具有以下属性:GetSemanticTargetForGeneration
GeneratorAttributeSyntaxContext
private static (ClassDeclarationSyntax, AttributeData) GetSemanticTargetForGeneration(GeneratorAttributeSyntaxContext context, CancellationToken ct)
{
if (!(context.TargetNode is ClassDeclarationSyntax classDeclaration))
return (null, null);
AttributeData attribute = context.Attributes
.FirstOrDefault(a => a.AttributeClass.Name == "EventApplyAttribute");
return (classDeclaration, attribute);
}
现在,我们将返回类声明和属性数据对。您可以在方法中处理它;我不知道你的目标是什么,所以在这里我只是生成一个文件,其中包含一个带有您正在寻找的类名的注释,以表明它有效:Execute
private static void Execute(Compilation compilation, ImmutableArray<(ClassDeclarationSyntax, AttributeData)> classes, SourceProductionContext context)
{
foreach (var (x, i) in classes.Select((x, i) => (x, i)))
{
TypedConstant aggregateParam = x.Item2.ConstructorArguments[0];
if (aggregateParam.Kind == TypedConstantKind.Primitive &&
aggregateParam.Value is string value)
{
context.AddSource(
$"generated_{i}.g.cs",
$"// <auto-generated/> using System; // Found param value '{value}'");
}
}
}
为了完整起见,您需要更改 main 方法:Initialize
public void Initialize(IncrementalGeneratorInitializationContext context)
{
IncrementalValuesProvider<(ClassDeclarationSyntax, AttributeData)> classDeclarations = context.SyntaxProvider
.ForAttributeWithMetadataName(
EventApplyAttribute,
predicate: static (node, _) => node is ClassDeclarationSyntax,
transform: static (ctx, ct) => GetSemanticTargetForGeneration(ctx, ct))
.Where(m => m.Item1 is not null && m.Item2 is not null);
IncrementalValueProvider<(Compilation, ImmutableArray<(ClassDeclarationSyntax, AttributeData)>)> compilationAndClasses
= context.CompilationProvider.Combine(classDeclarations.Collect());
context.RegisterSourceOutput(compilationAndClasses,
static (spc, source) => Execute(source.Item1, source.Item2, spc));
}
评论
0赞
Dani
10/3/2023
非常感谢,这很好用。找到一个像 aggregateParam.Value 这样的类的最佳方法是什么?
0赞
Dani
10/10/2023
从 x.Item1 我可以获取所有属性。但我还需要基类的属性,在本例中为 BaseEvent。如何访问 BaseEvent 属性名称?
评论
AttributeList
GetSemanticTargetForGeneration