如何通过源生成器基于所有转换节点聚合生成源代码文件
基于所有转换节点聚合生成单个源代码文件的解决方案
要实现基于所有MyEnumData聚合生成单个文件,你需要使用Incremental Generator的**Collect()**方法将分散的IncrementalValuesProvider<MyEnumData>转换为IncrementalValueProvider<ImmutableArray<MyEnumData>>,这样就能一次性获取所有转换后的节点数据,再生成单个文件。
具体实现步骤
- 聚合所有数据:在现有
IncrementalValuesProvider<MyEnumData>链后调用Collect()方法,将多个数据项合并为一个不可变数组的增量提供器。 - 注册单个文件生成逻辑:针对聚合后的增量提供器注册源输出,在处理逻辑中遍历整个数组生成代码。
修改后的完整代码示例
public void Initialize(IncrementalGeneratorInitializationContext context) { // 原有的数据收集与转换逻辑 IncrementalValuesProvider<MyEnumData?> sources = context.SyntaxProvider .ForAttributeWithMetadataName( MyEnumAttributeFullName, predicate: (node, _) => node is EnumDeclarationSyntax, transform: MyTransform) .WithTrackingName("Gathering") .Where(static node => node is not null) .WithTrackingName("RemovingNulls"); // 聚合所有MyEnumData为单个ImmutableArray IncrementalValueProvider<ImmutableArray<MyEnumData>> aggregatedSources = sources.Collect(); // 注册源输出,处理整个聚合后的数组 context.RegisterSourceOutput(aggregatedSources, static (context, allEnumData) => { ExecuteForAll(context, allEnumData); }); } // 处理所有聚合数据的方法 private static void ExecuteForAll(SourceProductionContext context, ImmutableArray<MyEnumData> allEnumData) { // 在这里编写生成单个文件的逻辑,比如构建注册表代码 StringBuilder codeBuilder = new StringBuilder(); codeBuilder.AppendLine("// 自动生成的枚举注册表"); codeBuilder.AppendLine("public static class EnumRegistry"); codeBuilder.AppendLine("{"); codeBuilder.AppendLine(" public static readonly IReadOnlyList<MyEnumData> AllEnums = new List<MyEnumData>"); codeBuilder.AppendLine(" {"); foreach (var enumData in allEnumData) { codeBuilder.AppendLine($" new MyEnumData(nameof({enumData.EnumName}), {enumData.ValueCount}),"); } codeBuilder.AppendLine(" };"); codeBuilder.AppendLine("}"); // 添加生成的源代码文件 context.AddSource("EnumRegistry.g.cs", codeBuilder.ToString()); }
关键说明
- Collect()方法:这是Incremental Generator提供的核心聚合API,它会将
IncrementalValuesProvider<T>转换为IncrementalValueProvider<ImmutableArray<T>>,确保高效的增量更新——只有当集合中的数据发生变化时,才会重新触发后续的生成逻辑。 - ImmutableArray:使用不可变数组保证线程安全和增量更新的可靠性,符合源生成器的编译时执行要求。
- 避免运行时反射:所有数据都是在编译时通过语法分析和转换获取的,完全不需要运行时反射操作,满足性能和设计需求。
内容的提问来源于stack exchange,提问作者Lance Grooms
相关产品推荐
相关产品推荐

