Roslyn脚本:运行时异常的行号信息 [英] Roslyn scripting: Line number information for run time exceptions

查看:249
本文介绍了Roslyn脚本:运行时异常的行号信息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Roslyn脚本的东西(使用 Microsoft.CodeAnalysis.CSharp.Scripting nuget包),我想知道是否有一种方法来添加行数字信息到堆栈跟踪,用于在脚本中发生的异常。



当我运行以下C#代码:

  // using Microsoft.CodeAnalysis.CSharp.Scripting; 

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

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

 在提交#0。<< Initialize>> d__0.MoveNext()
---从上一个位置结束堆栈跟踪异常被抛出---
在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务)
在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)
在Microsoft.CodeAnalysis .Scripting.ScriptExecutionState。< RunSubmissionsAsync> d__9`1.MoveNext()
---从抛出异常的前一个位置的堆栈跟踪结束---
在System.Runtime.CompilerServices.TaskAwaiter。 ThrowForNonSuccess(任务任务)
在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)
在Microsoft.CodeAnalysis.Scripting.Script`1。< RunSubmissionsAsync> d__21.MoveNext()
---从前一个位置的堆栈跟踪结束,异常发生wn ---
在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务)
在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)
在System.Runtime.CompilerServices .TaskAwaiter`1.GetResult()
在UnitTests.ExploreRoslyn。< ScriptWithRuntimeError> d__4.MoveNext()在D:\dev\misc\\\
etmockery\UnitTests\ExploreRoslyn.cs:line 47

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

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

输出:

 在提交#0。<< Initialize>> d__0.MoveNext()

到控制台。



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

解决方案

p>我有一些工作通过发出一个(内存)程序集的调试信息。



示例代码:

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

try
{
等待任务;
}
catch(DivideByZeroException dbze)
{
Console.WriteLine(dbze.StackTrace);
}

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

 在提交#0。<< Initialize>> d__0.MoveNext()in:line 3 
- - 从抛出异常的前一个位置的堆栈跟踪结束 - -
在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务)
在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)
在System.Runtime.CompilerServices.TaskAwaiter `1.GetResult()
在UnitTests.ExploreRoslyn。< ExploreEmittingAssembly> d__13.MoveNext()在D:\dev\misc\\\
etmockery\UnitTests\ExploreRoslyn.cs:行151

现在显然这是一个黑客,对于硬编码的脚本引擎实现细节我并不满意(提交#0 < Factory> ),另外我不知道我在做什么。应该有(也许有吗?)更好的方法。



更新



创建的问题 https://github.com/dotnet/roslyn/issues/13482 在Roslyn问题追踪器中。 / p>

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?

解决方案

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.

这篇关于Roslyn脚本:运行时异常的行号信息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆