Search code examples
c#lambdaexpression-trees

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?


Solution

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