Roger Alsing Weblog

Linq Expressions – Access private fields

with 10 comments

In this post I will show how you can use Linq Expressions to access private(or public) class fields instead of using Reflection.FieldInfo.

Normally when you want to access a field by its name on a type you have to resort to reflection.
You will end up with something like this:

FieldInfo field = MyType.GetField("someField",BindingFlags.NonPublic | .... );
object res = field.GetValue (MyObj);

This suffers from allot of drawbacks, it’s ugly, it’s untyped and its horribly slow to access data via FieldInfo.

Instead of playing around with FieldInfo, you can now use Linq Expressions to build a typed delegate that does this for you.

Here is how you do it:

public static Func<T,R> GetFieldAccessor<T,R>(string fieldName)
{
  ParameterExpression param =
  Expression.Parameter (typeof(T),"arg");  

  MemberExpression member =
  Expression.Field(param, fieldName);   

  LambdaExpression lambda =
  Expression.Lambda(typeof(Func<T,R>), member, param);   

  Func<T,R> compiled = (Func<T,R>)lambda.Compile();
  return compiled;
}

So what does this method do?
The first line in it will create a parameter expression, that is an argument that will be passed into our delegate eventually.

The next line creates a member expression, that is the code that access the field we want to use.
If you look at the code, you will see that we create an expression that access fields (Expression.Field) and that the first arg is the parameter we created before and the 2nd arg is the name of the field we want to access.
So what it does is that it will access the named field on the object that we pass as an argument to our delegate.

The 3rd line is where we create our lambda expression.
The lambda expression is the template for our delegate, we describe what we want to pass into it and what we want to get out of it.

The last part of the code will compile our lambda into a typed delegate: Func<T,R>, where T is the type of the argument we want to pass it and R is the type of the result we want to get out of it.

Here is an example on how to use this code:

Person person = new Person();
person.FirstName = "Roger";
var getFirstName = GetFieldAccessor<Person,string> ("firstName");
...
//typed access via delegate
string result = getFirstName(person);

Also do note that the “firstName” arg is the name of the field we want to access, not the property that I access in the sample.

This approach is also much faster than Reflection.FieldInfo.
I made a little benchmark where I accessed the same field a million times.

The Reflection.FieldInfo approach took 6.2 seconds to complete.
The Compiled lambda approach took 0.013 seconds to complete.
That’s quit a big difference.

So with this approach you can optimize your old reflection code and get some serious performance gains..

Well, that’s all for now.

Enjoy.

//Roger

kick it on DotNetKicks.com

See also:

Written by Roger Alsing

February 26, 2008 at 2:34 pm

Posted in .NET, C#, Linq

Tagged with , , ,

10 Responses

Subscribe to comments with RSS.

  1. Very nice work. As far as I understand this approach is that much faster since the expression is compiled, am I right? So I’d like to see benchmarks where the GetFieldAccessor-method is called for each iteration, this would indicate how it peforms when the resulting function is called only once. Seems to me that the lambda approach should be slower in that case, but I’d be glad if I were wrong.

    Patrik Hägne

    February 26, 2008 at 10:35 pm

  2. Yes the compilation phase is quite slow, much slower than the reflection approach.

    So if you intend to read a single field once, then reflection will be better.

    But for any scenario where you are likely to access the same field on different objects, then the lambda approach is much better.
    In such case you will most likely have to cache the field accessor in a dictionary or some other lookup structure.

    Roger Alsing

    February 26, 2008 at 11:12 pm

  3. This is really cool. I’m currently using reflection to get ALL the private fields in a class and then loop over them. Do you know if there is a similar approach that I could use with Linq that would provide the same speed increase?

    Rob

    February 27, 2008 at 2:44 pm

  4. @Rob

    Well I guess you could simply use reflection to find the field names, and then use those names to create your fieldAccessors and store the fieldaccessors in a dictionary.

    that way, you would only need to fetch the field names once per type and then you can use the fieldAccessors every time you need to read/write data.

    (ok I didnt provide a sample on how to write data, but thats doable in the same way, you just need to alter the lambda generator slightly)

    Roger Alsing

    February 27, 2008 at 2:50 pm

  5. > ok I didnt provide a sample on how to write data, but thats doable in the same way
    Is it? I didn’t think it was; I’d love to see a sample of this?

    Also: if the main objective is speed (rather than “private”), then another viable alternative [property based] is HyperDescriptor; fundamentally the same concept, but uses Reflection.Emit [it predates 3.5]; but has the advantage that it can “set”, and doesn’t need any special coding (in fact, the caller doesn’t even know you’ve switched to a faster implementation, as long as they are using PropertyDescriptor to start with):

    http://www.codeproject.com/KB/cs/HyperPropertyDescriptor.aspx

    Marc Gravell

    February 28, 2008 at 4:02 pm

  6. >>Is it? I didn’t think it was; I’d love to see a sample of this?

    I think I might have been a bit too fast on that conclusion.

    Calling set properties is possible since you can make method calls and setters are simply a void method in IL.

    But apparently its not possible to assign field values through expressions.

    So my bad on that one. :-/
    I did know that you cant use assignments in expressions in normal code, so I should have figured out that its not possible when building expressions either…
    *equips donkey ears*

    Roger Alsing

    February 28, 2008 at 6:40 pm

  7. I was skeptical of your testing, so I tried it myself. I measured 0.1 seconds for Lambda and 5.3 seconds for reflection.
    However, I need to assign both fields and properties inside an automated data class.
    If you ever determine how to do the assignments I would like to know. My data class code is fast but if I ever have very large data sets, the reflection time could begin to show in my performance.

    Mike Gillson

    October 1, 2008 at 5:02 pm

  8. [...] my old post “Linq Expressions: Access private fields” is by far my most read blog entry, I figured that I have to throw you some more [...]

  9. Hi Roger,

    I would like to know how to call an Expression on a ParameterExpression. I generated a GroupBy Expression thru this code,

    >>
    public IQueryable GenerateGroupByExpression(string groupByName) {
    ParameterExpression paramExpression = Expression.Parameter(SourceType, SourceType.Name);
    MemberExpression memExp = Expression.PropertyOrField(paramExpression, groupByName);
    LambdaExpression lambda = Expression.Lambda(memExp, paramExpression);
    //.GroupBy()
    var groupedSource = this.Source.Provider.CreateQuery(Expression.Call(
    typeof(Queryable),
    “GroupBy”,
    new Type[] {
    SourceType,
    SourceType.GetProperty(groupByName).PropertyType
    },
    Source.Expression,
    lambda
    )
    );
    //.Select()
    ParameterExpression groupparamExpression = Expression.Parameter(groupedSource.ElementType, “g”);
    List bindings = new List();
    bindings.Add(Expression.Bind(typeof(GroupContext).GetMember(”Key”)[0], Expression.PropertyOrField(groupparamExpression, “Key”)));
    bindings.Add(Expression.Bind(typeof(GroupContext).GetMember(”Count”)[0], Expression.Call(typeof(Queryable),
    “Count”,
    new Type[] { groupedSource.ElementType },
    new Expression[] { groupedSource.Expression })));
    bindings.Add(Expression.Bind(typeof(GroupContext).GetMember(”Details”)[0], groupparamExpression));
    Expression e = Expression.MemberInit(Expression.New(typeof(GroupContext)), bindings.ToArray());
    //g=>prop.Propertyname
    LambdaExpression selectLambda = Expression.Lambda(e, groupparamExpression);
    return groupedSource.Provider.CreateQuery(Expression.Call(
    typeof(Queryable),
    “Select”,
    new Type[] { groupedSource.ElementType, typeof(GroupContext) },
    new Expression[] { groupedSource.Expression, selectLambda }
    ));
    }

    >>

    I have a GroupContext class with Key, Count and Details as parameters in it. Let me know your thoughts on this Dynamic query.

    -Fahad

    Fahad

    January 5, 2009 at 5:43 am

  10. [...] Now we can dive into our expression trees. As a warm-up, here’s a relatively simple cached field accessor, inspired by Roger Alsing’s great post: [...]


Leave a Reply