如何让C# Source Generator访问引用项目中的代码?
解决C# Source Generator无法扫描引用项目类型的问题
要让Source Generator识别到引用项目中的类型,核心是利用编译上下文提供的完整编译信息,而非局限于当前测试项目的语法树,具体分两种场景处理:
场景1:引用的源项目是项目引用(源码参与编译)
如果测试项目直接引用了包含Person等Record的源项目(源码形式),你需要:
- 不要在代码中过滤语法树的来源,直接遍历
GeneratorExecutionContext.Compilation.SyntaxTrees的所有元素,这个集合包含整个编译流程中所有参与的语法树(包括引用项目的)。 - 移除任何针对测试项目文件路径的筛选逻辑,比如不要用
tree.FilePath.Contains("TestProject")这类条件限制扫描范围。 - 对每个语法树进行语义分析,通过
compilation.GetSemanticModel(tree)获取语义模型,再从中提取Record类型的符号信息。
示例代码片段:
public void Execute(GeneratorExecutionContext context) { var compilation = context.Compilation; // 遍历所有语法树,包括引用项目的 foreach (var syntaxTree in compilation.SyntaxTrees) { var semanticModel = compilation.GetSemanticModel(syntaxTree); // 查找语法树中的Record声明节点 var recordDeclarations = syntaxTree.GetRoot().DescendantNodes() .OfType<RecordDeclarationSyntax>(); foreach (var record in recordDeclarations) { var typeSymbol = semanticModel.GetDeclaredSymbol(record) as INamedTypeSymbol; if (typeSymbol != null && typeSymbol.DeclaredAccessibility == Accessibility.Public) { // 基于类型符号生成工厂代码 GenerateFactoryCode(context, typeSymbol); } } } }
场景2:引用的源项目是已编译程序集(如Nu包或DLL)
如果源项目是作为已编译程序集被引用的,此时不存在对应的语法树,需要通过编译上下文的符号系统来获取类型信息:
- 使用
compilation.GetTypeByMetadataName("YourNamespace.Person")直接通过元数据名称获取类型符号,确认类型存在后再生成代码。 - 或者遍历全局命名空间下的所有类型,筛选出符合条件的Record类型:
示例代码片段:
public void Execute(GeneratorExecutionContext context) { var compilation = context.Compilation; // 遍历全局命名空间下的所有类型 var globalNamespace = compilation.GlobalNamespace; var publicRecords = GetAllPublicRecords(globalNamespace); foreach (var recordSymbol in publicRecords) { GenerateFactoryCode(context, recordSymbol); } } private IEnumerable<INamedTypeSymbol> GetAllPublicRecords(INamespaceSymbol namespaceSymbol) { foreach (var member in namespaceSymbol.GetMembers()) { if (member is INamedTypeSymbol typeSymbol && typeSymbol.IsRecord && typeSymbol.DeclaredAccessibility == Accessibility.Public) { yield return typeSymbol; } else if (member is INamespaceSymbol nestedNamespace) { foreach (var nestedRecord in GetAllPublicRecords(nestedNamespace)) { yield return nestedRecord; } } } }
额外注意事项
- 确保引用项目中的Record类型是public的,Source Generator无法访问internal类型,除非在源项目中添加
[InternalsVisibleTo("YourTestProject")]特性。 - 如果使用了
SyntaxReceiver,检查是否在OnVisitSyntaxNode中添加了不必要的文件路径过滤,移除后它会处理所有语法树的节点。
内容的提问来源于stack exchange,提问作者Complexity
相关产品推荐
相关产品推荐

