How can I get objects and property values from expression trees?

How can I get objects and property values from expression trees?

  • Comments 5

This is a follow-up to the Getting Information About Objects, Types, and Members with Expression Trees post, so I would recommend that you read that one first.

Among other code examples in that blog post, I demonstrated how you can get a property name as a string by using expression trees. Here is the method.

public static string GetName<T>(Expression<Func<T>> e)
{
    var member = (MemberExpression)e.Body;
    return member.Member.Name;
}

And here is how you can use it.

string str = "Test";
Console.WriteLine("{0} : {1}",
GetName(() => str.Length), str.Length);
// Prints Length : 4

When you go deep into expression trees, you may need to get the actual value of the property or the reference to the containing object out of the expression itself. I’m going to show some tricks using simple and contrived examples, but remember that scenarios when you really need to do this are usually much more advanced. (Think about LINQ providers.)

Let’s say I want to create a method that prints not only the name of a property, but also the value of the property. Such a method might look like this.

public static void PrintProperty<T>(Expression<Func<T>> e)
{
    var member = (MemberExpression)e.Body;
    string propertyName = member.Member.Name;
    T value = e.Compile()();
    Console.WriteLine("{0} : {1}", propertyName, value);
}

Now let’s look closely at this magic line:

T value = e.Compile()();

In general, T is the type of the value that the expression produces. To simplify the example, the code only works for expressions like 
()=>obj.Property
. So in this case, T is the type of the property.

To get the property value, I need to compile this expression into a delegate and then invoke the delegate. In fact, I can write two separate lines of code instead of the shorter syntax used above:

Func<T> del = e.Compile();
T value = del();

So far, so good. Now I have a method that prints both the property name and its value:

string str = "Test";
PrintProperty(() => str.Length);
// Prints Length : 4

Let’s take it one step further. Suppose that I want this method to print not only the property value, but also the string itself:

String: Test
Length : 4

How can I do this? If I have an expression like () => str.Length, I can parse it like this:

public static void PrintPropertyAndObject<T>(Expression<Func<T>> e) 
// e represents "()=>str.Length"
{
    MemberExpression member = (MemberExpression)e.Body; 
    // member represents "str.Length"

    Expression strExpr = member.Expression; 
    // strExpr represents "str"

    . . .     
}

The object I need is now represented by strExpr. However, I can’t compile this expression into a delegate.

String resultStr = strExpr.Compile()(); // Compiler error here.

Only lambda expressions can be compiled into delegates. The problem is that strExpr is not a lambda expression.

Luckily, there is a trick that solves this problem. You can convert expressions into lambda expressions by using the Expression.Lambda<Tdelegate>() method. So, if I have an expression that represents "str", this method converts it to "()=>str".

To use this method, I need to specify a type of the delegate for the lambda expression. ()=>str returns string, so I am going to use Func<String> here.

// Converting the expression into a lambda expression.
Expression<Func<string>> lambdaExpr = Expression.Lambda<Func<string>>(strExpr);

Now I can compile and invoke lambdaExpr:

// Compiling the lambda expression into a delegate.
Func<String> del = lambdaExpr.Compile();

// Invoking the delegate.
String resultStr = del();

Or I can use shorter syntax and combine these three lines of code into one:

String resultStr = Expression.Lambda<Func<String>>(member.Expression).Compile()();

Of course, if strExpr is not a string, I get a runtime exception. But I can check whether it is a string by using the Expression.Type property.

if (strExpr.Type == typeof(String))
{
    String str = Expression.Lambda<Func<String>>(strExpr).Compile()();
    Console.WriteLine("String: {0}", str);
}

And here is the whole method:

public static void PrintPropertyAndObject<T>(Expression<Func<T>> e) 
{
    MemberExpression member = (MemberExpression)e.Body; 
    Expression strExpr = member.Expression; 
    if (strExpr.Type == typeof(String))
    {
        String str = Expression.Lambda<Func<String>>(strExpr).Compile()();
        Console.WriteLine("String: {0}", str);
    }
    string propertyName = member.Member.Name;
    T value = e.Compile()();
    Console.WriteLine("{0} : {1}", propertyName, value);
}

Once again, remember that this is a contrived example. I definitely would not recommend using this technique to print the value of a string object. But it might come in handy when you are debugging or analyzing complex expression trees.

Last but not least, remember that compiling expression trees is not a fast operation. So do not overuse it, or the performance of your application may degrade.

P.S.

Special thanks to Bill Chiles for patiently reading and reviewing three different versions of this post.

Leave a Comment
  • Please add 1 and 7 and type the answer here:
  • Post
  • This style of programming (get property name from expression) has become popular for the MVVM pattern and to have compile time checks for strings that represent property/method names. This works fine for these use cases. But wouldn't it be much easier to introduce a nameof() language extension so that the compiler could resolve a name. Even Prism (MS P&P) have resorted to declaring class names using const string members so they can use the class names in attributes. This is especially nice when working with MEF. So why not add C# support for things like [Export(nameof(MyClass))] or NotifyPropertyChanged(nameof(MyClass.MyProperty))?

  • I have often wondered why at least a propertyof() method for properties that functioned similarly to the typeof() method for types was never baked-in. It would have eliminated many needless errors introduced by using string literals to denote property names. Although it's a performance hit, I have started using the" () => PropertyName " lambda convention myself on both my view and domain models. When I refactor, I don't want to have to worry about forgetting to update a literal string...

  • To get any object even if it is not an string you can use the non-generic version of Expression.Lambda as follows:

    public static object GetObject<T>(Expression<Func<T>> expression)

           {

               MemberExpression memberExpression = expression.Body as MemberExpression;

               var objExpression = memberExpression.Expression;

               return Expression.Lambda(objExpression, null).Compile().DynamicInvoke(null);

           }

  • Thanks for this informative post.

    Do you have any idea what the performance difference is between using ExpressionTrees as mentioned above vs. Reflection?

    Thank you for your time.

  • Nice presentation. I m trying to learn this. thank you.

Page 1 of 1 (5 items)