2016-09-18 3 views
1

Cas bien évident. Je fais de la magie d'exécution avec des expressions. Mon test d'unité génère une exception car, bien, ce que je fais est assez complexe et donc évident à l'échec. Je ne sais pas comment je pourrais éventuellement déboguer le délégué généré, alors comme solution de contournement je voudrais insérer un try-catch qui enregistre l'exception à la console. Je ne comprends tout simplement pas comment je peux accéder à la variable d'exception.Exception d'accès dans l'expression générée à l'exécution

La variable est exposée par la classe CatchBlock. Mais je dois passer à travers le corps dans la méthode d'usine, où il est hors de portée.

Comment puis-je y accéder? Je ne vois aucune façon légitime et non-hacky de le faire et puisque c'est un sujet très inhabituel, il n'y a pratiquement pas de documentation/information à trouver sur internet.

Voici mon code à ce jour:

// The actual code 
BlockExpression block = Expression.Block(new[] {messageParam, objectParam}, 
    callExpressions.ToArray()); 

// The catch block around it 
CatchBlock catchExpression = Expression.Catch(typeof(Exception), 
    Expression.Call(typeof(Console).GetMethod(nameof(Console.WriteLine), 
      BindingFlags.Public | BindingFlags.Static, null, CallingConventions.Any, new[] {typeof(string)}, 
      null), 
     Expression.Call(// Here should be the ParameterExpression 
      typeof(Exception).GetProperty(nameof(Exception.Message), 
       BindingFlags.Public | BindingFlags.Instance).GetMethod))); 
// The try-block for the catch 
TryExpression tryExpression = Expression.TryCatch(block, catchExpression); 

// Compilation ... 
+0

Vous pouvez afficher les expressions "code" générées au fur et à mesure dans le débogueur. Donc, vous pouvez voir où vous allez mal. Vous ne serez pas en mesure de voir le code généré après l'avoir compilé. Donc, au fur et à mesure que je le développe, je colle simplement l'Expression.Lamba finale dans une variable temporaire que je vais supprimer quand tout fonctionnera. De cette façon, je serai en mesure de voir le code final. De plus, comme vous voyez le code généré, cela aura plus de sens si tout est lié - du moins c'est pour moi :). Publiez votre code généré si vous rencontrez des problèmes. – SledgeHammer

+0

Ah d'accord, donc je peux voir le code quand je regarde dans le LambdaExpression avant de le compiler? Bon à savoir. Eh bien, j'ai trouvé mon problème en utilisant la méthode de brainstorming à l'ancienne. J'ai passé les paramètres en tant que variables dans le bloc, les remplaçant ainsi causant une exception NullReferenceException. - Le problème s'est manifestement produit pendant l'exécution - la génération de code elle-même n'échoue pas puisqu'elle est valide. – SharpShade

Répondre

1

Je tentais désespérément de résoudre le même problème. J'ai des raisons très similaires - des fins de traçage sur les expressions dynamiques. La solution a fini par être aussi facile que d'utiliser un different overload of Expression.Catch.

Bien que - en raison de la documentation très clairsemée et des exemples, il était difficile à trouver.

Donc, au cas où quelqu'un d'autre a besoin d'une fonctionnalité similaire - va ici un exemple de travail très basique (vous pouvez remplacer le corps de capture avec l'expression personnalisée se connectant à votre enregistreur, etc.):

var parExcep = Expression.Parameter(typeof (Exception), "exc"); 

MethodInfo excMsg = typeof(Exception).GetProperty("Message", 
    BindingFlags.Public | BindingFlags.Instance).GetMethod; 


TryExpression tryCatchExpr = 
    Expression.TryCatch(
     Expression.Block(
      Expression.Throw(Expression.Constant(new DivideByZeroException())), 
      Expression.Constant("Try block") 
      ), 
     Expression.Catch(
      parExcep, 
      Expression.Call(parExcep, excMsg) 
      ) 
     ); 

Console.WriteLine(Expression.Lambda<Func<string>>(tryCatchExpr).Compile()()); 

Imprime:

Tentative de division par zéro.