Comment capturer un arbre d'expression en C #

c# expression-trees

Question

J'écris un code de débogage / test dans lequel je veux à la fois afficher l'expression d'origine et l'évaluer, pour toute expression arbitraire.

Pour exemple (trivial):

IList<string> myString = /* Some string collection expression */

ShowMe(myString.Select(s => s.ToLower()));

ShowMe quelque chose comme:

public void ShowMe(/* Not sure what has to go here */)
{
    /* Not sure what has to go here */
    Console.WriteLine(expression.ToString();
    IEnumerable result = expression.Evaluate(); // or something
    foreach(item in result)
    {
        Console.WriteLine(/* etc. */)
    }
}

Et le résultat sera écrit sur la console en tant que:

myString.Select (s => s.ToLower ())

(premier article)

(prochain point

(etc...)

En d'autres termes, ma méthode ShowMe opère sur l'arbre des expressions plutôt que sur la valeur de l'expression, de sorte qu'elle puisse afficher l'expression qui lui a été donnée ainsi que le résultat calculé.

Je ne peux pas simplement déclarer ShowMe comme:

public void ShowMe(Expression expr)

... mais si je déclare est comme

public void ShowMe(Expression<Func<Enumerable>> expr)

... c'est en quelque sorte un travail - je dois appeler ma méthode avec une expression lambda ainsi:

ShowMe(() => myString.Select(s => s.ToLower()))

... ce que je ne veux pas faire.

Je suis raisonnablement sûr que cela peut être fait ... FluentAssertions le fait. Par exemple: si j'exécute la ligne suivante du code de test:

(1 + 1).Should.Be(3)

J'obtiens le résultat suivant:

Attendu (1 + 1) égal à 3, mais trouvé 2.

FluentAssertion a à la fois évalué l'expression (1 + 1) et capturé l'arbre d'expression afin qu'il soit en mesure d'afficher l'expression originale évaluée.

Je ne vois pas comment cela a été fait, mais je veux faire la même chose. Comment fait-on ça?

Réponse acceptée

Cela n’est en soi possible avec aucune méthode.

Toutes ces bibliothèques ne font qu'analyser la trace de la pile et extraire le nom du fichier ainsi que le numéro de ligne. Ensuite, l'expression est extraite du fichier de code source à la ligne donnée (alors que cela inclut une partie de l'analyse / validation).

C'est également notamment que l'expression ne peut pas être affichée, si le code source n'existe pas / n'est pas disponible.


Réponse populaire

Compris un compromis acceptable:

public static class ObjectHelper
{
    public static void ToConsole<T>(this IEnumerable<T> enumerable, Expression<Func<T,object>> expr)
        where T:class
    {
        var fn = expr.Compile();

        var result = enumerable.Select(s => fn(s));

        Console.WriteLine($"My data selected as {PrettyPrintExpression(expr)}");
        foreach(var element in result)
        {
            Console.WriteLine(/*  etc.  */);
        }
    }

    private static string PrettyPrintExpression(Expression<Func<T,object>> expr)
    {
        // Walk the expression tree to print as desired
    }
}

... que je peux invoquer comme:

IList<MyObject> list = /* etc. */
list.ToConsole(s => new{/* any members I want out of MyObject */});



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