Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Expression tree - how to get at declaring instance?

I'm a newbie when it comes to expression trees, so I'm not sure how to ask this question or what terminology to use. Here's an overly-simplifed version of what I'm trying to do:

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

How can I get to bar inside the Zap method?

like image 594
Judah Gabriel Himango Avatar asked Dec 17 '22 03:12

Judah Gabriel Himango


1 Answers

Since the expression passed into your Zap method is a tree, you just need to walk the tree using an Expression Tree Visitor and look for the first ConstantExpression in the expression. It will likely be in the following sequence:

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

Note that the bar instance is captured by a closure, which is implemented as an internal class with the instance as a member, which is where the 2nd MemberExpression comes from.

EDIT

Then you have to get the field from the generated closure like so:

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

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

    public static void Zap<T>(Expression<Func<T>> source)
    {
        var param = (((source.Body as MemberExpression).Expression as MemberExpression).Expression as ConstantExpression).Value;
        var type = param.GetType();
        // Note that the C# compiler creates the field of the closure class 
        // with the name of local variable that was captured in Main()
        var field = type.GetField("bar");
        var bar = field.GetValue(param) as Bar;
        Debug.Assert(bar != null);
        Console.WriteLine(bar.Foo);
    }
like image 140
codekaizen Avatar answered Jan 06 '23 15:01

codekaizen