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

如何获取程序集中所有类型的源代码/SyntaxTree(Roslyn分析器测试用)

我之前也遇到过类似的困扰——用System.Reflection加载程序集后,根本拿不到源代码或语法树相关的信息,毕竟Assembly对象是针对编译后的IL字节码设计的,和Roslyn的语法树完全不在一个层面上。下面给你两种可行的解决方案,取决于你有没有对应的调试符号(PDB文件):

方案一:借助PDB文件关联到SyntaxTree

如果你的程序集有对应的PDB文件(Debug编译默认会生成),可以通过Roslyn的API加载程序集和符号信息,进而关联到类型对应的SyntaxTree和源代码。

先确保你的项目引用了Microsoft.CodeAnalysis和Microsoft.CodeAnalysis.CSharp NuGet包,然后试试这段代码:

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System.Reflection;
using System.IO;

// 获取目标程序集的物理路径
string assemblyPath = typeof(TypeWithinAssembly).Assembly.Location;
// 对应的PDB文件路径(默认和程序集同目录,后缀为.pdb)
string pdbPath = Path.ChangeExtension(assemblyPath, ".pdb");

// 创建包含符号信息的元数据引用
var metadataReference = MetadataReference.CreateFromFile(
    assemblyPath,
    new MetadataReferenceProperties(),
    pdbPath);

// 创建临时编译对象,用于访问符号信息
var compilation = CSharpCompilation.Create("TempTestCompilation")
    .AddReferences(metadataReference);

// 获取程序集的符号对象
if (compilation.GetAssemblyOrModuleSymbol(metadataReference) is IAssemblySymbol assemblySymbol)
{
    // 遍历程序集里的所有类型(包括嵌套类型)
    foreach (var typeSymbol in assemblySymbol.GlobalNamespace
        .GetTypeMembers()
        .SelectMany(t => t.GetTypeMembers())
        .Concat(assemblySymbol.GlobalNamespace.GetTypeMembers()))
    {
        // 遍历类型的所有源码位置
        foreach (var location in typeSymbol.Locations)
        {
            if (location.SourceTree != null)
            {
                SyntaxTree syntaxTree = location.SourceTree;
                string filePath = syntaxTree.FilePath;
                string sourceCode = syntaxTree.GetText().ToString();
                
                // 这里就拿到了类型对应的文件路径和源代码
                Console.WriteLine($"类型: {typeSymbol.Name}, 所在文件: {filePath}");
            }
        }
    }
}

方案二:直接从项目文件加载Compilation(适合测试自己的分析器)

如果你的测试目标是自己开发的项目,更高效的方式是直接用Roslyn加载项目文件,获取完整的Compilation对象,这样可以直接拿到所有的SyntaxTree,不需要依赖编译后的程序集和PDB。

代码示例:

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.MSBuild;

// 创建MSBuild工作区
using var workspace = MSBuildWorkspace.Create();
// 加载你的项目文件(替换成实际的.csproj路径)
var project = await workspace.OpenProjectAsync(@"C:\YourProject\YourProject.csproj");
// 获取项目的编译对象
var compilation = await project.GetCompilationAsync();

if (compilation != null)
{
    // 遍历项目里的所有SyntaxTree
    foreach (var syntaxTree in compilation.SyntaxTrees)
    {
        string filePath = syntaxTree.FilePath;
        string sourceCode = syntaxTree.GetText().ToString();
        
        // 从语法树中提取所有类型声明
        var root = await syntaxTree.GetRootAsync();
        var typeDeclarations = root.DescendantNodes().OfType<TypeDeclarationSyntax>();
        
        foreach (var typeDecl in typeDeclarations)
        {
            // 获取类型的语义符号
            var typeSymbol = compilation.GetSemanticModel(syntaxTree).GetDeclaredSymbol(typeDecl);
            if (typeSymbol != null)
            {
                Console.WriteLine($"类型: {typeSymbol.Name}, 所在文件: {filePath}");
            }
        }
    }
}

一些关键注意事项

  • 方案一中,必须保证PDB文件和程序集是同一编译输出的,否则符号信息不匹配,拿不到正确的源码位置。
  • 发布版本的程序集默认可能生成精简版PDB,或者直接省略源码位置信息,测试时建议用Debug编译。
  • 使用MSBuildWorkspace时,需要确保你的环境有正确的MSBuild支持(比如安装了Visual Studio,或者在项目中引用了Microsoft.CodeAnalysis.MSBuild NuGet包)。

内容的提问来源于stack exchange,提问作者5Wagga

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:06:33