Peter Heß
Peter Heß

Reputation: 58

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

I run into troubles using the Roslyn Scripting Engine. I get no exception handling when I run a script within a delegation.

Test that works as expected:

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

Result: No Assertion. The Exception was thrown.

Here's the text using a delegate object:

Unittest:

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

I got the fail message and no exception was thrown.

We cache the delegates to speed up the compilation and during a test we see that runtime exceptions are not thrown. So I wrote the test to reproduce this situation.

I can't find any hint in the docs which describes that there are no exceptions thrown during the invoke.

Can someone give me a pointer or a hint why this happens?

Upvotes: 2

Views: 752

Answers (2)

Cee McSharpface
Cee McSharpface

Reputation: 8726

Your Main finishes execution before the scheduler gets a chance to invoke delegat. It is a task that will run asynchronously. You can see that when you inspect it in the debugger:

enter image description here

To force execution inside the scope of the try...catch, you can use this:

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

The correct type of exception to expect in this case is the AggregateException, see here why.

A solution with await is also possible:

await delegat();

but this will compile only when the containing method can be marked async which is not necessarily what you want (show more of the calling code to clarify).

Upvotes: 0

svick
svick

Reputation: 244827

There are two issues with your code:

  1. In the first version, you're catching Exception, which means that when the Assert.Fail is reached and throws AssertionException, that exception is then caught and ignored.

    This means that there is no difference between RunAsync and delegate here, neither of them throws DivideByZeroException.

  2. Both RunAsync and the ScriptRunner<T> delegate return Task. That means to actually wait for them to complete or to observe any exceptions, you need to use await. Once you do that, you will see the DivideByZeroException that you're expecting.

Upvotes: 2

Related Questions