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

Roslyn scripting engine does not throw runtime exception when used as delegate

我 运行 在使用 Roslyn 脚本引擎时遇到了麻烦。当我 运行 委托中的脚本时,我没有得到任何异常处理。

按预期工作的测试:

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...
}

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

我们缓存委托以加快编译速度,并且在测试期间我们发现 运行time 异常没有被抛出。所以我写了测试来重现这种情况。

我在文档中找不到任何描述调用期间没有抛出异常的提示。

有人能给我指点或提示为什么会这样吗?

您的代码有两个问题:

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

    意思就是这里的RunAsync和delegate没有区别,都不会抛出DivideByZeroException.

  2. RunAsyncScriptRunner<T> 代表 return Task。这意味着要实际等待它们完成或观察任何异常,您需要使用 await。执行此操作后,您将看到您期望的 DivideByZeroException

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

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

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

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

也可以用await解决:

await delegat();

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