Arbre d'expression - comment en arriver à déclarer une instance?

c# expression-trees lambda

Question

Je suis un débutant en matière d'arbres d'expression, je ne sais donc pas comment poser cette question ni quelle terminologie utiliser. Voici une version simplifiée de ce que j'essaie de faire:

Bar bar = new Bar();
Zap(() => bar.Foo);

public static void Zap<T>(Expression<Func<T>> source)
{
   // HELP HERE:
   // I want to get the bar instance and call bar.Zim() or some other method.
}

Comment puis-je accéder à la méthode Zap?

Réponse acceptée

Comme l'expression transmise à votre méthode Zap est un arbre, il vous suffit de parcourir l'arborescence à l'aide d'un visiteur de l'arbre d' expression et de rechercher le premier objet ConstantExpression dans l'expression. Ce sera probablement dans l'ordre suivant:

(((source.Body as MemberExpression).Expression as MemberExpression).Expression as ConstantExpression).Value

Notez que l'instance de bar est capturée par une fermeture, qui est implémentée en tant que classe interne avec l'instance en tant que membre, d'où provient la 2nd MemberExpression.

MODIFIER

Ensuite, vous devez obtenir le champ à partir de la fermeture générée comme ceci:

(((source.Body as MemberExpression).Expression as MemberExpression).Expression as ConstantExpression).Value

Réponse populaire

Si vous connaissez le type de "barre", vous pouvez le faire (je réutilise quelques extraits de la réponse du codekaizen ici):

    static void Main(string[] args)
    {
        var bar = new Bar();
        bar.Foo = "Hello, Zap";
        Zap(() => bar.Foo);

        Console.ReadLine();
    }

    private class Bar
    {
        public String Foo { get; set; }
    }

    public static void Zap<T>(Expression<Func<T>> source)
    {
        var body = source.Body as MemberExpression;
        Bar test = Expression.Lambda<Func<Bar>>(body.Expression).Compile()();
        Console.WriteLine(test.Foo);
    } 

Dans la plupart des cas, vous pouvez trouver une expression représentant votre objet dans un arbre d'expression, puis compiler et exécuter cette expression et obtenir l'objet (mais ce n'est pas une opération très rapide, en passant). Ainsi, le peu que vous manquiez est la méthode Compile (). Vous pouvez trouver un peu plus d’informations ici: Comment: exécuter des arbres d’expression .

Dans ce code, je suppose que vous passez toujours une expression comme "() => object.Member". Pour un scénario réel, vous devrez soit analyser que vous avez une expression dont vous avez besoin (par exemple, déclenchez une exception si ce n'est pas une expression MemberExpression). Ou utilisez ExpressionVisitor, qui est un peu délicat.

J'ai récemment répondu à une question très similaire: comment puis-je m'abonner à un événement d'un objet dans un arbre d'expression?




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