Roslyn脚本编制:运行时异常的行号信息

时间:2016-08-31 07:58:11

标签: c# debugging scripting roslyn

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

当我运行以下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.<<Initialize>>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.<RunSubmissionsAsync>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.<RunSubmissionsAsync>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.<ScriptWithRuntimeError>d__4.MoveNext() in D:\dev\misc\netmockery\UnitTests\ExploreRoslyn.cs:line 47

请注意,如果我尝试在脚本中捕获异常,结果类似:

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.<<Initialize>>d__0.MoveNext()

到控制台。

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

1 个答案:

答案 0 :(得分:1)

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

示例代码:

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("<Factory>");
var submissionArray = new object[2];
Task<object> task = (Task<object>)factory.Invoke(null, new object[] { submissionArray });

try
{
    await task;
}
catch (DivideByZeroException dbze)
{
    Console.WriteLine(dbze.StackTrace);
}

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

   at Submission#0.<<Initialize>>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.<ExploreEmittingAssembly>d__13.MoveNext() in D:\dev\misc\netmockery\UnitTests\ExploreRoslyn.cs:line 151

现在很明显这是一个黑客攻击,我对硬编码的脚本引擎实现细节(Submission#0<Factory>)并不满意,而且我不会这样做真的知道我在做什么。应该有(也许有?)更好的方法。

更新

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