Geeks With Blogs

@darrenkopp
  • darrenkopp Can't wait to get back into Utah. May just have to drive all night... about 436 days ago
  • darrenkopp @iamic my email is twitter username @gmail.com. my vacation is ending tomorrow so I'll have time to look tomorrow night about 436 days ago
  • darrenkopp @xpaulbettsx heard other people complain about it, but not sure that it has happened to me before. about 439 days ago
  • darrenkopp Hello again salt lake city about 440 days ago
  • darrenkopp ... And belt jam at baggage claim. Thanks, Seattle. Now I sit. about 441 days ago
  • darrenkopp @kevinmontrose how so? i vastly prefer android UI paradigm to iOS. Especially once they added fragments about 442 days ago
  • darrenkopp @codinghorror fair enough. it is still slow for that processor though. who said anything about it gaining you anything? :) about 442 days ago

Darren's Blog Where sense and sensibility don't meet

Currently I'm working on a data synchronization tool in which I have finally had the need to use reflection. I'll admit that I'm not an expert when it comes to reflection, but it isn't that hard to work with either. And I have heard before about the performance hit you take with reflection, so up until now I hadn't ever needed / wanted to use it, but I see now the power that reflection offers.

One day while perusing my RSS feeds for the day I was reading one of Scott Hanselman's weekly source code posts in which the Ukadc.Diagnostics project uses Lightweight Code Generation (LCG) to speed up the retrieval of the value of a property using reflection. Pretty slick, but what I need is a faster way to SET the value of a property without knowing it's type. Now, like I said before, I'm no reflection guru, nor am I an IL guru, but I thought I would give it a shot. Epic Fail.

I'm kind of thick headed though when it comes to a problem, I usually don't give up unless I'm sure I can't win, and I'm not giving up. So I decided go try doing this the C# 3.0 way, where I don't have to IL generate anything. Ultimately, there is IL being generated, as reported by Reflector, but I'm not generating it, so all is well.

So first off, lets list our requirements.

  1. Improve performance of getting / setting properties via PropertyInfo
  2. Getter / Setter
    1. Support for known type and known return type
    2. Support for known type and unknown return type
    3. Support unknown type and unknown return type

For this post, I'm only going to cover FastProperty, but in the attachment I'll include the files to support item #1 and item #2 when parts are unknown (FastProperty<T,P> and FastProperty<T>). The only real differences between each one is gradually replacing object for it's generic counterpart.

So first, lets take a step back and talk about what a property actually is. If we want to set a property, we would just do something like

Employee e = new Employee();

e.ID = 4;

All is fine and well. But a property is just syntactic sugar over a method. In this instance we would have a set method called void set_ID(Integer) and a get method called Integer get_ID(). So what we really want to do is make a delegate for these methods. So to begin with, lets tackle the easiest method, the get method.

The Code

public class FastProperty

{

    public PropertyInfo Property { get; set; }

 

    public Func<object, object> GetDelegate;

    public Action<object, object> SetDelegate;

 

    public FastProperty(PropertyInfo property)

    {

        this.Property = property;

        InitializeGet();

        InitializeSet();

    }

 

    private void InitializeSet()

    {

        var instance = Expression.Parameter(typeof(object), "instance");

        var value = Expression.Parameter(typeof(object), "value");

 

        // value as T is slightly faster than (T)value, so if it's not a value type, use that

        UnaryExpression instanceCast = (!this.Property.DeclaringType.IsValueType) ? Expression.TypeAs(instance, this.Property.DeclaringType) : Expression.Convert(instance, this.Property.DeclaringType);

        UnaryExpression valueCast = (!this.Property.PropertyType.IsValueType) ? Expression.TypeAs(value, this.Property.PropertyType) : Expression.Convert(value, this.Property.PropertyType);

        this.SetDelegate = Expression.Lambda<Action<object, object>>(Expression.Call(instanceCast, this.Property.GetSetMethod(), valueCast), new ParameterExpression[] { instance, value }).Compile();

    }

 

    private void InitializeGet()

    {

        var instance = Expression.Parameter(typeof(object), "instance");

        UnaryExpression instanceCast = (!this.Property.DeclaringType.IsValueType) ? Expression.TypeAs(instance, this.Property.DeclaringType) : Expression.Convert(instance, this.Property.DeclaringType);

        this.GetDelegate = Expression.Lambda<Func<object, object>>(Expression.TypeAs(Expression.Call(instanceCast, this.Property.GetGetMethod()), typeof(object)), instance).Compile();

    }

 

    public object Get(object instance)

    {

        return this.GetDelegate(instance);

    }

 

    public void Set(object instance, object value)

    {

        this.SetDelegate(instance, value);

    }

}

Getter

The get method returns a value and takes no inputs, so we are going to use the Func<T,TResult> delegate because we want to return a value. Now, don't freak out because that delegate takes in a parameter, but the method signature doesn't, the input is the instance you are calling the property on. This is what we are basically going to do:

   Func<object,object> getter = instance => return instance.Property;

or more correctly

   Func<object,object> getter = instance => return instance.get_Property();

We are just going to represent this as an Expression tree. So lets get down to the nitty gritty. All of our wonderful expression stuff lives in the System.Linq.Expresssions namespace. To recreate our lambda expression we would do the following. If we look at the InitializeGet method, we start off by declaring a parameter called instance. This basically just saying that we'll be passing in a parameter of type object into our lambda called instance. The next thing that we do is create an UnaryExpression that is casting our parameter from the type of object to the type of the property.

Why are we casting from object to the type you ask? Well, because we don't know the type before compile time, we have to use a delegate of type Func<object,object>, so in order to create that delegate, we have to match that signature. But we also are going to be calling the get method on our instance variable, which isn't of type object, so we are casting it.

So now, we are going to call the get_<Property> method. So we create an MethodCallExpression via the Expression.Call method and pass in the instance of our object, which is properly cast to the correct type, and the get method for the property, via PropertyInfo.GetGetMethod(). But guess what, we have a delegate that is expecting a return value of type object back, not what the get_<Property> is actually returning (unless it happens to be object), so we do another Expression.TypeAs to convert the value back to object.

Now finally we get the delegate for all of our hard work, so we call the Expression.Lambda<T> method and pass our expression, and any parameters needed for it, which we only have 1 of, which is our instance, and then finally call the Compile method on our LambdaExpression which will gives us our Func<object,object> delegate.

Simple as pie right? Well, if you kept up with all that, we should be able to figure out the setter.

Setter

The set method is a void and takes exactly 1 parameter, so we are going to use the Action<T1,T2> delegate. So what we are basically wanting to do is this:

   Action<object, object> setter = (instance, value) => instance.Property = value;

or more correctly

   Action<object, object> setter = (instance, value) => instance.set_Property(value);

So to begin with, we create parameters for instance, and for value, both of type object. Then what do we do next? Well, we cast them back to their proper type. Now we are going to call the method, just like we did with the get method, but we are going to pass in a parameter - value. Now all we need to do is create our Lambda and compile. And we are done.

Performance

For this performance test, I'm using the Get/Set implementation put forth by Pete the CodeSlinger which uses IL Generation and DynamicMethod, the Expression Tree method which I have put forth, the "classic" reflection approach, and, of course, the native approach.

For 10,000,000 iterations, here is the time in milliseconds for each approach. The results are kind of creepy in the way the it's almost a mirror on each side of the decimal point.

  1. Native
    1. Get - 169.0169
    2. Set - 1874.1874
  2. PropertyCaller<T,K>
    1. Get - 389.0389
    2. Set - 1966.1966
  3. FastProperty<T,P>
    1. Get - 301.0301
    2. Set - 1956.1956
  4. FastProperty<T>
    1. Get - 470.047
    2. Set - 2247.2247
  5. FastProperty
    1. Get - 516.0516
    2. Set - 2277.2277
  6. PropertyInfo
    1. Get - 7313.7313
    2. Set - 14163.4162
  7. MethodInfo - via PropertyInfo.GetGetMethod / PropertyInfo.GetSetMethod
    1. Get - 6960.696
    2. Set - 13702.3701

As we can see, using Expression Trees we can get MUCH better performance than using the standard reflection methods even when we don't know type or return type. And the only performance penalty we pay is for boxing. Also, each FastProperty call up there assumes calling the Set / Get method on the FastProperty instance. If we call the actual delegate (GetDelegate and SetDelegate) we actually achieve better performance than the PropertyCaller delegates in the FastProperty<T,P> instance, and the difference between then FastProperty<T> and FastProperty instances is 3 milliseconds on the get, and 19 milliseconds on the set.

The more you know before hand, the better.

So, although I don't think it needs to be stated, I will, just to be thorough. The more you know before hand, the better this will perform. So, if you don't know the type you will be using, or the return type, use FastProperty. If you know the type, but not the return type of the property, use FastProperty<T> because then you can avoid the casting. It's not a terrible performance hit, but developers are perfectionists, lets not kid ourselves. And if you are just going to want to get a property of a type, for whatever reason (you should be going native, but I don't know your situation) then use FastProperty<T,P>.

Where to go next?

Well, I'm just laying out the framework that I have built, I'll leave it up to you to do whatever you want. It's faster to invoke the delegates than to call the Get / Set method on the FastProperty class, but I leave that there to allow you to add error handling (i.e. you can see if the value is assignable from the property.PropertyType, and throw an exception there instead of it coming up from the delegate code, which will be hard to track down).

Source

You can pick up all the source for this over at the FastReflection project at code.msdn.com. I'll probably be moving this over to codeplex eventually and supported more things via reflection (fields, methods?), we'll see. For now, i'm just going to put everything up at code.msdn.com.

License

This code is released under the "OMG LOL go pwn the developer next to you with this new knowledge" license. Ok not really, I'm just putting Ms-PL for code.msdn.com, which I believe lets you do anything you want. If not, let me know and I'll change the license. Hopefully this has been helpful for all who stumble upon this.

Happy .NETing,
Darren

Posted on Friday, June 27, 2008 5:18 PM Development , .NET | Back to top


Comments on this post: Faster Reflection using Expression Trees

# re: Faster Reflection using Expression Trees
Requesting Gravatar...
Hello, Darren!

This sounds pretty interesting for my case. What I want to do is to configure WebControls (or more specifically 3rd party ASP.NET-controls) dynamically during runtime.

A set of stored procedures will return metadata for the webcontrols, which will decide the looks and behaviour for the controls.
For instance, it the control is a grid, the metadata will contain things like if multi-item selection is allowed, the background-color of rows, etc.

The metadata is XML-based, so in the example above, it would be something like:
<grid>
<property name="AllowMultiSelection" value="true />
<ItemStyle>
<property name="BackColor" value="blue" />
</ItemStyle>
</grid>

I could do this the native way, like:
grid.AllowMultiSelection = bool.Parse(xmlData.SelectSingleNode("[@name=AllowMultiSelection]").Value)
etc
(My XPath syntax is completely wrong, it's just pseudo-code to prove my point)

Since there are sooo many different properties on these webcontrols, it would be a lot of work to implement the way above.
Instead, I am thinking of using reflection, but there are two things that bother me:
Performance is the first, but this might not be such a huge problem, with your work.

The second is what would be the best way to actually implement this. It's not too hard to set the properties on the "root-level", i.e. the grid itself (like the AllowMultiSelection property above). But how do I get to the BackColor-property of the ItemStyle-property, without using (slow) reflection?

Or am I going the wrong way here? Actually, all the properties and their datatypes are known beforehand, so I could use reflection to generate code that would parse the XML-data and (natively) set the properties' values. But that code would be rather difficult to implement, I think...


Do you have any comments on this subject?

Thanks!
/Fredrik
Left by Fredrik on Jul 17, 2008 2:55 PM

# re: Faster Reflection using Expression Trees
Requesting Gravatar...
Fredrik,

Right now i'm doing xml mapping of properties w/ the fast reflection library. it runs the basic structure of

<class>
<property>
// various information
</property>
</class>

To answer your question, first, i don't think you would see much of a problem w/ performance. We're looking at millions of get or sets that are sub second, so i doubt it would be much of a performance hit.

The only gotcha that you would run into is type conversion. You would probably need to use the TypeConverter for the property type to convert from the xml values. But seeing as how you can declaratively set the property values on the data grid in the source of the asp.net page, all the values should be convertable from a string value.

TypeDescriptor class (to get type converter): http://msdn.microsoft.com/en-us/library/ewtxwhzx.aspx

Scott Hanselman blog entry on using type converter: http://www.hanselman.com/blog/TypeConvertersTheresNotEnoughTypeDescripterGetConverterInTheWorld.aspx
Left by Darren Kopp on Jul 17, 2008 9:34 PM

# re: Faster Reflection using Expression Trees
Requesting Gravatar...
Really it is Good and most wanted for me such type of code,

Great Code

Regards
Upen
Left by upen on Sep 21, 2011 3:30 AM

Your comment:
 (will show your gravatar)
 


Copyright © Darren Kopp | Powered by: GeeksWithBlogs.net | Join free