当用作委托时,Roslyn脚本引擎不会抛出运行时异常

时间:2017-09-12 17:57:12

标签: c# exception-handling roslyn

我使用Roslyn Scripting Engine遇到了麻烦。我在委托中运行脚本时没有异常处理。

测试按预期工作:

string script = @"var a=0; var b=2/a;";
var runner = CSharpScript.Create<object>(script);
var errors = runner.Compile();
Assert.IsTrue(errors.IsEmpty);

try
{
    runner.RunAsync();
    Assert.Fail("Where is the exception");
}
catch (System.Exception)
{
    // everything is OK! Error thrown...
}

结果:没有断言。抛出异常。

这是使用委托对象的文本:

单元测试:

string script = @"var a=0; var b=2/a;";
var runner = CSharpScript.Create<object>(script);
var errors = runner.Compile();
var delegat = runner.CreateDelegate();
Assert.IsTrue(errors.IsEmpty);

try
{
    delegat();
    Assert.Fail("Where is the exception?");
}
catch (System.DivideByZeroException)
{
    // everything is OK! Error thrown...
}

我收到了失败消息,没有抛出任何异常。

我们缓存代理以加速编译,在测试期间我们看到不会抛出运行时异常。所以我写了测试来重现这种情况。

我在文档中找不到任何提示,说明在调用期间没有抛出异常。

有人可以给我一个指针或暗示为什么会发生这种情况?

2 个答案:

答案 0 :(得分:2)

您的代码存在两个问题:

  1. 在第一个版本中,您正在捕获Exception,这意味着当达到Assert.Fail并抛出AssertionException时,会捕获并忽略该异常

    这意味着此处RunAsync和委托之间没有区别,它们都不会抛出DivideByZeroException

  2. RunAsyncScriptRunner<T>委托都返回Task 。这意味着要实际等待它们完成或观察任何异常,您需要使用await。完成后,您会看到您期待的DivideByZeroException

答案 1 :(得分:0)

您的Main在调度程序有机会调用delegat之前完成执行。这是一个异步运行的任务。在调试器中检查它时可以看到:

enter image description here

要强制执行try...catch范围内的执行,您可以使用:

try
{
    delegat().Wait();
}
catch(System.AggregateException ex)
{
    /* the inner exception of ex will be your DivideByZeroException */
}

在这种情况下,正确的异常类型是AggregateExceptionsee here why

也可以使用await的解决方案:

await delegat();

但是只有当contains方法可以标记为async时才会编译,这不一定是你想要的(显示更多要调用的调用代码)。