Roslyn脚本:运行时exception的行号信息

我正在搞乱使用Roslyn脚本编写的东西(使用Microsoft.CodeAnalysis.CSharp.Scripting nuget包),我想知道是否有办法在脚本中发生exception的堆栈跟踪中添加行号信息。

当我运行以下C#代码时:

 // using Microsoft.CodeAnalysis.CSharp.Scripting; var code = @" var a = 0; var b = 1 / a; "; try { await CSharpScript.RunAsync(code); } catch (DivideByZeroException dbze) { Console.WriteLine(dbze.StackTrace); } 

写入控制台的堆栈跟踪是:

  at Submission#0.<>d__0.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.CodeAnalysis.Scripting.ScriptExecutionState.d__9`1.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.CodeAnalysis.Scripting.Script`1.d__21.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() at UnitTests.ExploreRoslyn.d__4.MoveNext() in D:\dev\misc\netmockery\UnitTests\ExploreRoslyn.cs:line 47 

请注意,如果我尝试捕获脚本中的exception,结果类似:

 var code = @" try { var a = 0; var b = 1 / a; } catch (System.DivideByZeroException dbze) { Console.WriteLine(dbze.StackTrace); } "; await CSharpScript.RunAsync(code); 

这输出:

 at Submission#0.<>d__0.MoveNext() 

到控制台。

有没有办法让Roslyn脚本引擎在编译/执行脚本时添加调试信息,所以我可以在堆栈跟踪中获取行号信息?

通过发出带有调试信息的(内存中)程序集,我得到了一些工作。

示例代码:

 var code = @" var a = 0; var b = 1 / a; "; var script = CSharpScript.Create(code); var compilation = script.GetCompilation(); var ilstream = new MemoryStream(); var pdbstream = new MemoryStream(); compilation.Emit(ilstream, pdbstream); var assembly = Assembly.Load(ilstream.GetBuffer(), pdbstream.GetBuffer()); var type = assembly.GetType("Submission#0"); var factory = type.GetMethod(""); var submissionArray = new object[2]; Task task = (Task)factory.Invoke(null, new object[] { submissionArray }); try { await task; } catch (DivideByZeroException dbze) { Console.WriteLine(dbze.StackTrace); } 

输出是(注意:line 3堆栈跟踪中的:line 3 ):

  at Submission#0.<>d__0.MoveNext() in :line 3 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() at UnitTests.ExploreRoslyn.d__13.MoveNext() in D:\dev\misc\netmockery\UnitTests\ExploreRoslyn.cs:line 151 

现在显然这有点像黑客,我对硬编码的脚本引擎实现细节( Submission#0 )并不满意,而且我真的不知道我在做什么。 应该(也许有?)更好的方法。

更新

在Roslyn问题跟踪器中创建了问题https://github.com/dotnet/roslyn/issues/13482 。