Getting Information About Objects, Types, and Members with Expression Trees

Getting Information About Objects, Types, and Members with Expression Trees

Rate This
  • Comments 17

Starting with C# 3.0 and Visual Studio 2008, you can use expression trees to get information about objects, types, and members. In this post I’m going to show some examples and explain what benefits you can get by using this technique. If you are not familiar with expression trees, I would recommend reading Charlie Calvert’s blog post Expression Tree Basics first.

Let’s start with a simple task. Assume that you want to print the name of a field or a property next to its value. For example, imagine that you have the following class.

public class SampleClass
{
    public string SomeField = "Test";
}

Of course, there is a straightforward solution:

SampleClass sample = new SampleClass();
Console.WriteLine("SomeField : {0}", sample.SomeField);
// Prints SomeField : Test

The problem with the above code is that you use a string literal SomeField. Nothing guarantees that this is the real name of the field. You might type the name incorrectly or just accidentally specify the wrong name. Furthermore, if you rename your property to, say, AnotherField, it could be hard to find a string literal that represents its name.

Here is how you can create a method that returns a property name by using expression trees, without using any string literals:

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

To call this method, you need to give it a lambda expression, as shown below.

Console.WriteLine("{0} : {1}",
    GetName(() => sample.SomeField), sample.SomeField);
// Also prints SomeField : Test

Because of the lambda expression, you get not only compile-time error checking, but also full IntelliSense support when typing a member name. And if you rename a property, the compiler will find all the places where the property name is used. Or you can rely on refactoring tools to rename all the instances of the property for you.

In fact, you can also use this method to get the name of the variable itself (which can be convenient for tracing and logging).

Console.WriteLine("{0} : {1}", GetName(() => sample), sample);
//Prints sample : SampleClass

The only problem with using a lambda expression is that you need to ensure that the user passes the correct one. For example, the user of your method can pass a lambda expression like () => new SampleClass(). Unfortunately, you can’t get a compile check for this. So, when using a lambda expression, make sure that you really get the expression you expect. For example, like this:

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

    // If the method gets a lambda expression
    // that is not a member access,
    // for example, () => x + y, an exception is thrown.
    if (member != null)
        return member.Member.Name;
    else
        throw new ArgumentException(
            "'" + e +
            "': is not a valid expression for this method");
}

One more scenario where expression trees can help you is getting information about members of a type. C# provides the typeof operator to get type information, but does not provide operators like memberof or infoof. You can use reflection methods such as Type.GetField(), Type.GetMethod(), and so on, but then you have to use string literals again.

// By using typeof operator, you can get type information
// without using string literals.
Type type = typeof(SampleClass);

// But to get information about a member by using reflection,
// you have to rely on string literals.
FieldInfo fieldInfo = type.GetField("SomeField");

Console.WriteLine(fieldInfo);
// Prints System.String SomeField

The problem gets worse if you have overloaded methods in your class.

public class SampleClass
{
    public string SomeField = "Test";
    public void SomeMethod() { }
    public void SomeMethod(string arg) { }
}

In this case, you need to specify a method and also its parameters.

MethodInfo methodInfo = type.GetMethod(
    "SomeMethod", new Type[] { typeof(String) });
Console.WriteLine(methodInfo);
// Prints Void SomeMethod(System.String)

Now you have more ways to get yourself into trouble. In addition to explicitly specifying the name of your method, you’ve also specified the number and types of its parameters. So any changes in the method signature can affect the behavior of your program, and the compiler will not detect it.

With expression trees you can get the same information without using string literals, and also get the compiler to check whether the member you need exists. Furthermore, all you need to do to get a necessary method overload is provide an example of the method usage within a lambda expression. Thanks to Mads Torgersen, a Visual Studio Program Manager, for providing the following code example.

public static MemberInfo MemberOf<T>(Expression<Func<T>> e)
{
    return MemberOf(e.Body);
}

// We need to add this overload to cover scenarios
// when a method has a void return type.
public static MemberInfo MemberOf(Expression<Action> e)
{
    return MemberOf(e.Body);
}

private static MemberInfo MemberOf(Expression body)
{
    {
        var member = body as MemberExpression;
        if (member != null) return member.Member;
    }

    {
        var method = body as MethodCallExpression;
        if (method != null) return method.Method;
    }

    throw new ArgumentException(
        "'" + body + "': not a member access");
}

Now you can use the MemberOf method for all kinds of scenarios, for both instance and static members.

Console.WriteLine(MemberOf(() => sample.SomeField));
// Prints System.String SomeField

// To choose a particular method overload,
//
you simply show the usage of the method.
Console.WriteLine(MemberOf(() => sample.SomeMethod("Test")));
// Prints Void SomeMethod(System.String)

Console.WriteLine(MemberOf(() => sample.SomeMethod()));
// Prints Void SomeMethod()

Console.WriteLine(MemberOf(() => Console.Out));
// Prints System.IO.TextWriter Out

I want to repeat that this functionality is already available in C# 3.0 and .NET Framework 3.5. If you want to know how expression trees are extended in .NET Framework 4, take a look at one of my previous posts: Generating Dynamic Methods with Expression Trees in Visual Studio 2010.

Update

See also a follow-up post: How can I get objects and property values from expression trees?

Leave a Comment
  • Please add 4 and 3 and type the answer here:
  • Post
  • Can you tell me what all the extra cases are in oliver hanappi's version at http://stackoverflow.com/questions/1329138/how-to-make-databinding-type-safe-and-support-refactoring

    are for or how they might be used? it seems much more complex than your code, and I'm trying to figure out how to utilize them.

    it's a switch on expression.NodeType that has cases for call, convert, and member access.

  • Hi Brandond,

    I looked at this question. What Oliver does is very similar to what I am doing here. He uses a switch and then makes a cast, while I do a cast and then check for null. I'd say it is a matter of taste which way to go.

    Also, his goal is always to return the name of the type member. I have covered only use cases for properties and fields, while he also shows how to return the name of the method. In my examples, I only show how to return MethodInfo for methods (you can get the name of the method from MethodInfo, anyway).

    Basically, he was answering a particular question and solving a particular problem. I was trying to show different ways how you can use expression trees and what benefits you can get by using them.

  • Thank you for these examples. They just helped me to experiment a little further with simplifying some code. Being able to remove further string constants and gaining compile time checking in exchange is definitely worth the time!

  • I'll be using this in the project Im currently working on. Thanks

  • Are you kidding ....

    SampleClass sample = new SampleClass();

    Console.WriteLine("SomeField : {0}", sample.SomeField);

    // Prints SomeField : Test

    This is perfect code, However if you use reflection, then you will have to enter it as a string, which can be a problem becase you wont know the error till Runtime.

    iF rename or anything, the above code will give compile time error which is perfect.

  • I take that back, it was my mistake :)

  • @ RN

    Glad that you saw it yourself :-) Of course I've been talking about string literals, not about the property name in a variable.

  • This is a obviously a powerful and extremely useful technique.  However (as one can see with a tool like ildasm) it still results in a lot of (in this case needless) code being generated and expression tree node objects being allocated, and therefore is not nearly as efficient as a hypothetical operator like "memberof" could be.  Given that, do you think there is any interest from Microsoft to support memberof/infoof?

  • @ Corey

    Yes, it is not a perfect solution. And I am not aware of any plans for "memberof".

    You can read Eric Lippert's post about some design complications with this feature:

    http://blogs.msdn.com/ericlippert/archive/2009/05/21/in-foof-we-trust-a-dialogue.aspx

  • We've been debating using this technique at my work for a while now.  Honestly I don't like it.  By using an expression tree you're changing the meaning of things.  At first glance it looks like you're passing in a lambda function that will be executed, but what you're really doing is passing in a lambda function that gets evaluated.  This is very confusing; especially for less seasoned C# developers that may not have a good grasp on lambda functions.  Additionally this technique isn't that type safe.  For example I could make the call this way:  GetName(()=> 1 + 2);, and that will compile.  At the end of the day I prefer a more straight forward approach; such as using constants.  Sure you need to update your constants whenever you change a property name, but once you've done that you will still enlist the compiler without creating a solution that will confuse many developers.

  • On a side note I think MS should consider providing strongly typed reflection to help us solve this problem.  Let's face with the advent of WPF, and the INotifyPropertyChanged event we need to know the names of properties in our code.  Right now we either need to employ this proposed solution, which I think could confuse a lot of developers, or we need to use string constants, which need to be updated as the code changes.  Neither solution is ideal.  I think that MS should provide strongly typed reflection by overloading the class keyword.  It would look something like this:

    class<Foo> fooReflector = new class<Foo>();

    if (e.PropertyName == fooReflector.Properties.Bar.Name)

    {

     //Code goes here.

    }

  • @Edgar

    I'd say this post falls more into "tips and tricks" category. It's not a guideline. And of course, expression trees (as well as reflection) is an advanced technique in general, so I personally would not recommend any novice developer to mess with it.

    Yes, it's not an ideal solution. But in some cases it might be more convinient than reflection.

    As for strongly typed reflection, I am not aware of such plans. But you are always welcome to post your suggestions at Microsfot Connect: http://connect.microsoft.com/VisualStudio

  • I had translate this article to chinese.

    我已将此文章翻译成中文:

    http://www.cnblogs.com/tianfan/archive/2010/03/07/getting-information-about-objects-types-and-members-with-expression-trees.html

  • Hi Brandon!

    My code is a bit more complex in order to handle more scenarios. For example I am allowing to get the name of a "sub-member" in dot notation and so on. But basically it is the same :)

    Oliver Hanappi

  • I show on my blog how I use this with INotifyPropertyChanged: weblogs.asp.net/.../PropertyOf-INotifyPropertyChanged-PropertyChanged-strings-infoof.aspx

Page 1 of 2 (17 items) 12