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

Roslyn Source Generators如何获取引用项目语义模型与源码

在Source Generator中获取引用项目语义模型与源代码的实现方法

Roslyn源生成器默认运行在目标项目的编译管线中,默认仅能直接访问当前目标项目(即示例中的TargetProject)的语法树与编译对象,被引用的RefProjectA、RefProjectB默认以编译后元数据的形式存在,需要根据你的需求选择对应实现方式:

获取引用项目的语义元数据(无需原始源码场景)

如果你的逻辑只需要获取引用项目的类型定义、成员签名、属性标注等编译后语义信息,不需要读取原始源码,不需要额外配置,直接通过现有编译对象即可获取:

  • 遍历context.Compilation.SourceModule.ReferencedAssemblySymbols拿到所有被引用的程序集符号
  • 通过程序集名称过滤出RefProjectA、RefProjectB对应的IAssemblySymbol实例
  • 拿到程序集符号后可直接通过符号API访问所有公开/内部(需要配置InternalsVisibleTo给源生成器)的类型、成员信息,所有语义查询逻辑和操作目标项目本地符号完全一致

注意:该方式仅能访问编译后保留在元数据中的信息,无法获取原始源码文本、注释、预处理指令、未编译进元数据的源码结构,性能最优,适合仅需要类型元数据的场景。

获取引用项目原始源码与对应语义模型(需要源码分析场景)

如果你需要分析RefProjectA的原始语法结构、源码文本,必须先修改项目配置传递源码,再在生成器中解析生成语义模型:

第一步:配置引用项目,向源生成器传递源码

在RefProjectA、RefProjectB的csproj文件中添加以下配置,将项目源码作为附加文件传递给上游项目的源生成器:

<ItemGroup>
  <!-- 将当前项目所有C#源码文件标记为附加文件,随项目引用传递 -->
  <AdditionalFiles Include="**/*.cs" />
  <!-- 给附加文件打来源标记,方便生成器识别文件所属项目 -->
  <CompilerVisibleItemMetadata Include="AdditionalFiles" MetadataName="SourceProject" Value="$(AssemblyName)" />
</ItemGroup>

请确保TargetProject对RefProjectA、RefProjectB的引用为ProjectReference类型,直接引用编译后dll无法触发附加文件的传递逻辑。

第二步:在生成器中解析源码生成语义模型

在生成器执行逻辑中按以下步骤处理:

  • 遍历context.AdditionalFiles集合,通过之前配置的SourceProject元数据,过滤出所有属于RefProjectA、RefProjectB的.cs源码文件
  • 对每个过滤出的文件调用GetText()获取原始源码文本,调用CSharpSyntaxTree.ParseText()将文本解析为Roslyn语法树
  • 基于TargetProject的原有Compilation对象,调用AddReferences()补充RefProjectA、RefProjectB的依赖程序集,再调用AddSyntaxTrees()把刚才解析出的引用项目语法树加入,得到新的Compilation实例
  • 对新的Compilation实例调用GetSemanticModel(syntaxTree),即可拿到对应引用项目语法树的语义模型,所有语义查询行为和本地项目的语义模型完全一致

踩坑提示:不要直接用TargetProject原始的Compilation对象为引用项目的语法树生成语义模型,会出现元数据不匹配、符号解析失败的问题,必须将引用项目的语法树和其依赖加入到同一个Compilation实例中再生成语义模型。

增量生成器优化写法

如果你使用的是IIncrementalGenerator,不要每次编译全量解析所有附加文件,可以通过增量提供器缓存解析结果,避免拖慢编译速度:

public void Initialize(IncrementalGeneratorInitializationContext context)
{
    // 过滤出属于RefProjectA的所有源码附加文件
    IncrementalValuesProvider<SyntaxTree> refProjectASyntaxTrees = context.AdditionalFilesProvider
        .Combine(context.AnalyzerConfigOptionsProvider)
        .Where(pair =>
        {
            var (file, configProvider) = pair;
            if (!file.Path.EndsWith(".cs")) return false;
            return configProvider.GetOptions(file)
                .TryGetValue("build_metadata.AdditionalFiles.SourceProject", out var projectName) 
                && projectName == "RefProjectA";
        })
        .Select((pair, token) =>
        {
            var (file, _) = pair;
            var sourceText = file.GetText(token);
            return CSharpSyntaxTree.ParseText(sourceText, cancellationToken: token);
        });

    // 将解析出的语法树和主编译对象组合,后续做增量语义分析即可
    var compilationWithRefA = context.CompilationProvider.Combine(refProjectASyntaxTrees.Collect());
}

内容的提问来源于stack exchange,提问作者Eike S

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 08:31:22