问题
I am messing around with the Roslyn scripting stuff (using the Microsoft.CodeAnalysis.CSharp.Scripting
nuget package), and I wonder if there is a way to add line number information to the stack traces for exceptions that happen inside a script.
When I run the following C# code:
// 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);
}
The stack trace written to the console is:
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
Note that if I try to catch the exception inside the script, the result is similar:
var code = @"
try {
var a = 0;
var b = 1 / a;
}
catch (System.DivideByZeroException dbze)
{
Console.WriteLine(dbze.StackTrace);
}
";
await CSharpScript.RunAsync(code);
This outputs:
at Submission#0.<<Initialize>>d__0.MoveNext()
To the console.
Is there a way to make the Roslyn scripting engine add debug information when compiling/executing the script, so I can get line number information in the stack trace?
回答1:
I got something working by emitting an (in-memory) assembly with debug information.
Example code:
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);
}
The output is (notice the :line 3
in the stack trace):
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
Now obviously this is a bit of a hack, and I'm not really happy with the hardcoded script engine implementation details (Submission#0
, <Factory>
), plus I don't really know what I'm doing. There should be (and maybe there is?) a better way.
Update
Created issue https://github.com/dotnet/roslyn/issues/13482 in the Roslyn issue tracker.
来源:https://stackoverflow.com/questions/39243866/roslyn-scripting-line-number-information-for-run-time-exceptions