You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 20:22:39