Expression tree - how to get to instance declaration?

I am new 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 simplified 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 do I access the Zap method?

+4
source share
3 answers

Since the expression passed to your Zap method is a tree, you just need to traverse the tree using Expression Tree Visitor and find the ConstantExpression expression in the expression. This will probably be in the following sequence:

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

Note that the bar instance is captured by the closure, which is implemented as an inner class with the instance as a member, where the second MemberExpression expression comes from.

EDIT

Then you should get the field from the generated closure like this:

  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); } 
+6
source

If you know the type "bar", you can do this (I reuse a few bits from the response to the codecase):

  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 most cases, you can find an expression representing your object in the expression tree, and then compile and execute that expression and get the object (but by the way, this is not a very fast operation). So, the bit you were missing is the Compile () method. You can find a little more information here: A practical guide. Run expression trees .

In this code, I assume that you always pass an expression like "() => object.Member". For a real-world scenario, you need to either analyze that you have an expression that you need (for example, just throw an exception if it is not MemberExpression). Or use ExpressionVisitor, which is quite complex.

I recently answered a very similar question: How do I subscribe to an object event inside an expression tree?

+5
source

Standing on the shoulders of the giants above, my last extension method for retrieving an instance of a class that is the source of an expression is as follows:

 public static TIn GetSource<TIn, TOut>(this Expression<Func<TIn, TOut>> property) where TIn: class { MemberExpression memberExpression = (MemberExpression)property.Body; TIn instance = Expression.Lambda<Func<TIn>>(memberExpression.Expression).Compile()(); return instance; } 

I built all the answers above, thanks everyone.

+1
source

All Articles