Partager via


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

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?

Comments

  • Anonymous
    January 08, 2010
    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.

  • Anonymous
    January 11, 2010
    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.

  • Anonymous
    January 22, 2010
    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!

  • Anonymous
    January 27, 2010
    I'll be using this in the project Im currently working on. Thanks

  • Anonymous
    February 03, 2010
    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.

  • Anonymous
    February 03, 2010
    I take that back, it was my mistake :)

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

  • Anonymous
    February 10, 2010
    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?

  • Anonymous
    February 10, 2010
    @ 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

  • Anonymous
    February 12, 2010
    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.

  • Anonymous
    February 12, 2010
    The comment has been removed

  • Anonymous
    February 15, 2010
    The comment has been removed

  • Anonymous
    March 06, 2010
    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

  • Anonymous
    June 04, 2010
    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

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

  • Anonymous
    May 18, 2012
    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.

  • Anonymous
    June 19, 2013
    The comment has been removed