Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Given a type ExpressionType.MemberAccess, how do i get the field value?

I am parsing an Expression Tree. Given a NodeType of ExpressionType.MemberAccess, how do I get the value of that Field?

From C# MSDN docs: MemberAccess is A node that represents reading from a field or property.

A code snippet would be incredibly, incredibly helpful. Thanks in advance!!!

My code looks something like this:

public static List<T> Filter(Expression<Func<T, bool>> filterExp) 
{
//the expression is indeed a binary expression in this case
BinaryExpression expBody = filterExp.Body as BinaryExpression;

if (expBody.Left.NodeType == ExpressionType.MemberAccess) 
  //do something with ((MemberExpressionexpBody.Left).Name

//right hand side is indeed member access. in fact, the value comes from //aspdroplist.selectedvalue            
if (expBody.Right.NodeType == ExpressionType.MemberAccess)
{
   //how do i get the value of aspdroplist.selected value?? note: it's non-static                        
}

//return a list
}
like image 968
Keith Fitzgerald Avatar asked Oct 26 '08 23:10

Keith Fitzgerald


2 Answers

[updated for clarity]

First; cast the Expression to a MemberExpression.

A MemberExpression has two things of interest:

  • .Member - the PropertyInfo / FieldInfo to the member
  • .Expression - the expression to evaluate to get the "obj" for the .Member

i.e. if you can evaluate the .Expression to "obj", and the .Member is a FieldInfo, then you can get the actual value via .GetValue(obj) on the FieldInfo (and PropertyInfo is very similar).

The problem is that evaluating the .Expression is very tricky ;-p

Obviously you get lucky if it turns out to be a ConstantExpression - but in most cases it isn't; it could be a ParameterExpression (in which case you'll need to know the actual parameter value that you want to evaluate), or any other combination of Expressions.

In many cases, a simple (perhaps lazy) option is to use .Compile() to get the .NET framework to do the heavy lifting; you can then evaluate the lambda as a typed delegate (passing in any parameters that the lambda requires). This isn't always an option, however.

To show how complex this is; consider this trivial example (where I've hard-coded at every step, rather than testing etc):

using System;
using System.Linq.Expressions;
using System.Reflection;
class Foo
{
    public string Bar { get; set; }
}

static class Program
{
    static void Main()
    {
        Foo foo = new Foo {Bar = "abc"};
        Expression<Func<string>> func = () => foo.Bar;

        MemberExpression outerMember = (MemberExpression)func.Body;
        PropertyInfo outerProp = (PropertyInfo) outerMember.Member;
        MemberExpression innerMember = (MemberExpression)outerMember.Expression;
        FieldInfo innerField = (FieldInfo)innerMember.Member;
        ConstantExpression ce = (ConstantExpression) innerMember.Expression;
        object innerObj = ce.Value;
        object outerObj = innerField.GetValue(innerObj);
        string value = (string) outerProp.GetValue(outerObj, null);    
    }

}
like image 179
Marc Gravell Avatar answered Nov 19 '22 15:11

Marc Gravell


thank you so so much to Marc Gravell above. I really appreciated his help.

It turns out, in my case. the problem can be solved via:

object value = Expression.Lambda(expBody.Right).Compile().DynamicInvoke();

Thanks again Mark!

like image 24
Keith Fitzgerald Avatar answered Nov 19 '22 13:11

Keith Fitzgerald