Ausdrucksbaum - Wie komme ich zur Instanz?

c# expression-trees lambda

Frage

Ich bin ein Neuling, wenn es um Ausdrucksbäume geht, also bin ich nicht sicher, wie man diese Frage stellt oder welche Terminologie zu verwenden ist. Hier ist eine übermäßig vereinfachte Version dessen, was ich versuche zu tun:

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

Wie kann ich innerhalb der Zap-Methode in die Bar gehen?

Akzeptierte Antwort

Da der an Ihre Zap Methode übergebene Ausdruck ein Baum ist, müssen Sie nur den Baum mit einem Expression Tree Visitor durchlaufen und nach dem ersten ConstantExpression im Ausdruck suchen. Es wird wahrscheinlich in der folgenden Reihenfolge sein:

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

Beachten Sie, dass die bar Instanz von einer Closure erfasst wird, die als interne Klasse mit der Instanz als Mitglied implementiert wird, von der der 2. MemberExpression stammt.

BEARBEITEN

Dann müssen Sie das Feld wie folgt aus dem generierten Abschluss holen:

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

Beliebte Antwort

Wenn Sie den Typ des "Balkens" kennen, können Sie dies tun (ich verwende einige Bits aus der Antwort des Codecaizen hier):

    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);
    } 

In den meisten Fällen können Sie einen Ausdruck finden, der Ihr Objekt in einer Ausdrucksbaumstruktur darstellt, und dann diesen Ausdruck kompilieren und ausführen und das Objekt erhalten (was übrigens keine sehr schnelle Operation ist). Das fehlende Bit ist also die Methode Compile (). Sie können ein wenig mehr Informationen hier finden: Gewusst wie: Ausführen von Ausdrucksbäumen .

In diesem Code gehe ich davon aus, dass Sie immer einen Ausdruck wie "() => object.Member" übergeben. Für ein realistisches Szenario müssen Sie entweder analysieren, dass Sie einen Ausdruck haben, den Sie brauchen (z. B. eine Ausnahme auslösen, wenn es sich nicht um eine MemberExpression handelt). Oder verwenden Sie ExpressionVisitor, was ziemlich kompliziert ist.

Ich habe kürzlich eine sehr ähnliche Frage beantwortet: Wie abonniere ich ein Ereignis eines Objekts in einem Ausdrucksbaum?




Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum