Search code examples
c#reflectionexpression-trees

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
}

Solution

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