2017-09-12 2 views
2

Je rencontre des problèmes avec le moteur de script Roslyn. Je ne reçois aucune exception lors de l'exécution d'un script dans une délégation.Le moteur de script Roslyn ne supprime pas l'exception d'exécution lorsqu'il est utilisé en tant que délégué

test qui fonctionne comme prévu:

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

Résultat: Non Assertion. L'exception a été lancée.

Voici le texte à l'aide d'un objet délégué:

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

Je suis le message d'échec et aucune exception a été levée.

Nous mettons en cache les délégués pour accélérer la compilation et lors d'un test, nous voyons que les exceptions d'exécution ne sont pas levées. J'ai donc écrit le test pour reproduire cette situation.

Je ne trouve aucun indice dans les documents qui décrivent l'absence d'exception lors de l'invocation. Est-ce que quelqu'un peut me donner un pointeur ou un indice pour que cela se produise?

Répondre

2

Il y a deux problèmes avec votre code:

  1. Dans la première version, vous attraper Exception, ce qui signifie que lorsque le Assert.Fail est atteint et lancers francs AssertionException, cette exception est alors capturé et ignoré.

    Cela signifie qu'il n'y a aucune différence entre RunAsync et déléguer ici, ni l'un ni l'autre DivideByZeroException.

  2. Les deux RunAsync et le délégué ScriptRunner<T>retour Task. Cela signifie que pour les attendre pour compléter ou observer les exceptions, vous devez utiliser await. Une fois que vous faites cela, vous verrez le DivideByZeroException que vous attendez.

+0

Merci, cela explique tout! Je n'ai pas réalisé le comportement asynchrone de delagates. Donc, je ne peux pas utiliser les délégués dans ma situation, parce que je ne veux pas avoir de threads spawnd pour les très petits scripts qui fonctionnent comme une sorte de déclencheur dans notre application. La seule solution que je vois est de mettre en cache les objets de compilation et non les délégués. Je vais à quelques tests de performance pour voir quelle solution fonctionne mieux. Merci pour la clarification. –

+1

@ PeterHeß Qu'est-ce qui vous fait penser que les fils de ponte vont être un problème? D'autant plus que lorsque le script n'utilise pas 'await', son exécution n'est pas vraiment asynchrone (même si un 'Task' est utilisé pour communiquer son résultat, ce qui rend' await' nécessaire). – svick

0

Votre Main termine l'exécution avant que le planificateur obtient une chance d'invoquer delegat. C'est une tâche qui fonctionnera de manière asynchrone. Vous pouvez voir que lorsque vous inspectez dans le débogueur:

enter image description here

Pour forcer l'exécution dans le cadre de la try...catch, vous pouvez utiliser ceci:

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

Le type correct d'exception à attendre dans ce cas est le AggregateException, see here why.

Une solution avec await est également possible:

await delegat(); 

mais recueille uniquement lorsque la méthode contenant peut être marqué async qui est pas nécessairement ce que vous voulez (montrer plus du code d'appel pour clarifier).

+0

La question dit que le code provient d'un test unitaire, donc il n'y a pas de 'Main'. Et même dans ce cas, assurez-vous simplement que 'Main' ne finit pas trop tôt, par ex. en utilisant 'Console.ReadLine()', ne serait pas utile. – svick

+0

Merci pour votre clarification. Voir ma réponse dans le message ci-dessous. –