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

Roslyn动态编译代码异常栈缺失行号问题求助

解决Roslyn动态编译异常无法获取行号的问题

我来帮你梳理下问题原因,以及对应的解决办法:

问题核心原因

你遇到的情况是:Visual Studio能显示异常行号,但通过StackTrace API拿不到行信息,本质是动态加载的程序集对应的源文件路径在运行时不存在,CLR无法从PDB中关联到有效的源文件信息。具体来说:

  • 你设置的sourceCodePath是"generated.cs",但这个文件并没有实际创建在当前运行目录下
  • 虽然你添加了EmbeddedText嵌入源信息,但CLR默认优先查找物理文件,导致无法直接从PDB中解析嵌入式源内容

两种可行解决方案

方案1:生成临时文件加载(最直接)

让CLR能找到对应的物理源文件和PDB文件,就能正常解析行号:

修改你的编译加载逻辑:

// 创建临时目录存放文件
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempDir);

// 定义文件路径
var assemblyPath = Path.Combine(tempDir, $"{assemblyName}.dll");
var pdbPath = Path.Combine(tempDir, symbolsName);
var sourcePath = Path.Combine(tempDir, sourceCodePath);

// 把生成的代码写入临时文件
File.WriteAllText(sourcePath, code, encoding);

// 编译输出到文件
EmitResult result = compilation.Emit(
    peStream: File.OpenWrite(assemblyPath),
    pdbStream: File.OpenWrite(pdbPath),
    embeddedTexts: embeddedTexts,
    options: emitOptions);

if (result.Success)
{
    Console.WriteLine("Kompilierung erfolgreich!");
    try
    {
        // 从文件加载程序集
        var assembly = Assembly.LoadFrom(assemblyPath);
        var parsedCodeInfo = new IM3ParsedCodeInfo() { Assembly = assembly, Erfolgreich = true };
        return parsedCodeInfo;
    }
    catch (Exception ex)
    {
        Console.WriteLine("Ausnahme aufgetreten:");
        Console.WriteLine(ex);
        var parsedCodeInfo = new IM3ParsedCodeInfo() { ErrorException = ex, Erfolgreich = false };
        return parsedCodeInfo;
    }
}

方案2:自定义AssemblyLoadContext(无临时文件)

如果不想生成物理文件,可以通过自定义加载上下文,让CLR直接从PDB的嵌入式源信息中读取行号:

首先定义自定义加载上下文:

public class DynamicAssemblyLoadContext : AssemblyLoadContext
{
    private readonly byte[] _pdbBytes;

    public DynamicAssemblyLoadContext(byte[] pdbBytes) : base(isCollectible: true)
    {
        _pdbBytes = pdbBytes;
    }

    protected override Assembly Load(AssemblyName assemblyName)
    {
        throw new NotImplementedException();
    }

    // 重写获取符号流的方法,返回我们的PDB字节流
    protected override Stream GetSymbolStream(string assemblyPath)
    {
        return new MemoryStream(_pdbBytes);
    }
}

然后修改加载逻辑:

if (result.Success)
{
    Console.WriteLine("Kompilierung erfolgreich!");
    try
    {
        var loadContext = new DynamicAssemblyLoadContext(symbolsStream.ToArray());
        var assembly = loadContext.LoadFromStream(assemblyStream);
        var parsedCodeInfo = new IM3ParsedCodeInfo() { Assembly = assembly, Erfolgreich = true };
        return parsedCodeInfo;
    }
    catch (Exception ex)
    {
        Console.WriteLine("Ausnahme aufgetreten:");
        Console.WriteLine(ex);
        var parsedCodeInfo = new IM3ParsedCodeInfo() { ErrorException = ex, Erfolgreich = false };
        return parsedCodeInfo;
    }
}

额外需要确认的点

  • 你的CSharpCompilationOptions已经设置OptimizationLevel.Debug,这是正确的(Release模式会丢失调试信息)
  • EmitOptions使用的PortablePdb格式是兼容的,无需修改
  • 捕获异常时new StackTrace(ex, true)的参数true必须传,这样才会收集文件和行号信息

按照上面的方案修改后,frame.GetFileLineNumber()就能返回正确的行号,stackTrace.ToString()也会包含完整的行信息了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:00:49