提问人:Dani 提问时间:10/9/2023 最后编辑:Dani 更新时间:10/10/2023 访问量:118
获取 C# 源代码生成中的基类属性 - IIncrementalGenerator
Get base class properties in C# source generation - IIncrementalGenerator
问:
我在源代码生成器中有以下 Execute 方法。我可以获取我的类的所有属性(x.Item1.Members.AsEnumerable()...)。但是我也无法获取基类的属性。如何列出基类的所有属性?
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 fullyQualifiedAggregateName)
{
var aggregateName = "Aggregate";
var props = x.Item1.Members.AsEnumerable().Where(o => o.IsKind(SyntaxKind.PropertyDeclaration));
var sb = new StringBuilder();
context.AddSource(
$"generated_{aggregateName}_{i}.g.cs",
sb.ToString());
}
}
}
更新
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));
}
private static (ClassDeclarationSyntax, AttributeData) GetSemanticTargetForGeneration(GeneratorAttributeSyntaxContext context, CancellationToken ct)
{
if (context.TargetNode is not ClassDeclarationSyntax classDeclaration)
{
return (null, null);
}
AttributeData? attribute = context.Attributes.FirstOrDefault(a => a.AttributeClass?.Name == "EventApplyAttribute");
return (classDeclaration, attribute);
}
答:
0赞
Marc Gravell
10/9/2023
#1
真的,你想要的是语义模型,而不是语法模型。而且你不需要等待 - 当使用增量生成器时,大概你正在使用 ,在语法模型上提供预过滤器,以及更灵活的转换。在该转换中,可以访问语义模型。这对性能是有利的,因为它允许缓存转换步骤中的任何处理,只要相关语法树没有失效。Execute
CreateSyntaxProvider
在转换过程中,您可以通过以下方式获取语义模型 - 您可能希望在 .由于这是声明一个类型,因此它给你的符号应该是 an 并且很可能是 .这意味着您现在拥有对类型数据的完全访问权限,包括 .ctx.SemanticModel
ctx.SemanticModel.GetDeclaredSymbol(...)
ClassDeclarationSyntax
ITypeSymbol
INamedTypeSymbol
.BaseType
但是:在转换或执行时,您可以获得语义模型
您还可以通过传入相关语法节点的语法树来获取语义模型,但是:如果您这样做,您可能会重复大量工作,从而对 IDE 性能产生不利影响。Execute
state.Compilation.GetSemanticModel(...)
评论
0赞
Youssef13
10/9/2023
除此之外,该步骤应生成一个值相等的自定义模型,该模型不得包含编译或符号。相反,它应该从编译/符号中提取它需要的东西。transform
0赞
Marc Gravell
10/9/2023
@Youssef13出于好奇,有什么引用吗?
1赞
Youssef13
10/9/2023
好吧,通过 Discord 频道与 Roslyn 团队聊天时,这些信息非常隐藏。但是在 github.com/dotnet/roslyn/blob/main/docs/features/ 有一个暗示......。顺便说一句,这就是为什么很难编写增量生成器或将现有的非增量生成器转换为增量生成器的原因。还可以查看生成器的示例 GH 问题,该生成器在管道 github.com/k94ll13nn3/AutoConstructor/issues/82 中包含编译。
评论
RegisterImplementationSourceOutput
Compilation
ImmutableArray<TSource>
TSource
ClassDeclarationSyntax
Compilation