Expression.Convert dans Expression.TryCatch

c# expression-trees

Question

J'essaie d'ajouter un traitement d'erreur à un bloc de code de la bibliothèque Effort, qui génère un arbre d'expression pour effectuer une conversion et affecter ce résultat à une propriété.

Le problème avec le code existant est qu'une exception NullReferenceException est levée lorsque cette expression est appelée à l'exécution lors de la tentative d'attribution de null à une propriété avec un type valeur. Dans ce cas, je n'ai aucune information sur la propriété qu'il tentait d'attribuer. Je souhaite donc lancer une exception plus spécifique.

Voici ma première tentative d'encapsuler cette logique dans un bloc try / catch et de lever une exception si la conversion échoue. Finalement, j'ajouterais plus d'informations à InvalidOperationException.

blockElements.Add(
    Expression.TryCatch(
        Expression.Assign(
            Expression.Property(result, this.Properties[i]),
            Expression.Convert(
                Expression.ArrayIndex(parameter, Expression.Constant(i)),
                this.Properties[i].PropertyType)),
        Expression.Catch(typeof(NullReferenceException),
            Expression.Throw(Expression.Constant(
            new InvalidOperationException("Unhandled exception"))))));

Dans mon esprit, voici ce que j'essaie de faire:

try
{
    Property = (int)value;
}
catch (NullReferenceException)
{
    throw new InvalidOperationException("Unhandled exception");
}

Toutefois, au moment de l'exécution, cette expression renvoie désormais une exception ArgumentException avec le message "Le corps de la capture doit avoir le même type que le corps de l'essai". Qu'est-ce que je fais mal ici? Dois-je créer un bloc dans l'expression Catch pour "renvoyer" une valeur factice, même si elle ne sera jamais touchée à cause du Throw?

Ou est-ce que j'aborde ce problème de manière totalement incorrecte?

Réponse acceptée

En code C # normal, une méthode dans son ensemble doit soit renvoyer une valeur, soit renvoyer une exception.

Avec Expression s, il fonctionne un peu différent: chaque expression a un type de retour, et dans le cas de TryCatch , le type de retour de l' try d' catch Expression Expression doit être le même que le type de retour de l' une des catch d' Expression s.

Dans votre cas, le type de try est int , mais le type de catch est void , elles ne peuvent donc pas être utilisées ensemble. Pour résoudre ce problème, vous devez changer le type de try d’ void ou modifier le type de catch en int .

Pour changer le type de try d’ void , vous pouvez utiliser une surcharge de Expression.Block() qui vous permet de spécifier le type du bloc (normalement, il est identique à celui de la dernière expression du bloc):

Expression.TryCatch(
    Expression.Block(
        typeof(void),
        Expression.Assign(…)),
    Expression.Catch(
        typeof(NullReferenceException),
        Expression.Throw(
            Expression.Constant(
                new InvalidOperationException("Unhandled exception")))))

Pour changer le type de catch en int , vous devez en quelque sorte changer le type de l'expression Throw . Et comme pour une expression Throw , tout type de retour peut être valide (car il ne renvoie pas réellement), il existe une surcharge qui vous permet de spécifier le type de retour :

Expression.TryCatch(
    Expression.Assign(…),
    Expression.Catch(
        typeof(NullReferenceException),
        Expression.Throw(
            Expression.Constant(
                new InvalidOperationException("Unhandled exception")),
            typeof(int))))

Je pense que changer le type d' try est conceptuellement plus clair, parce que vous ne voulez vraiment rien renvoyer de l'expression entière.




Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi