Reflection Performance - Create Delegate (Properties C#)
Asked Answered
M

3

29

I'm having performance problems with using reflection.
So I decided to create delegates for the properties of my objects and so far got this:

TestClass cwp = new TestClass();
var propertyInt = typeof(TestClass).GetProperties().Single(obj => obj.Name == "AnyValue");
var access = BuildGetAccessor(propertyInt.GetGetMethod());
var result = access(cwp);
static Func<object, object> BuildGetAccessor(MethodInfo method)
{
    var obj = Expression.Parameter(typeof(object), "o");

    Expression<Func<object, object>> expr =
        Expression.Lambda<Func<object, object>>(
            Expression.Convert(
                Expression.Call(
                    Expression.Convert(obj, method.DeclaringType),
                    method),
                typeof(object)),
            obj);

    return expr.Compile();
}

The results were highly satisfactory, about 30-40 times faster than using the conventional method (PropertyInfo.GetValue (obj, null);)

The problem is: How can I make a SetValue of a property, which works the same way? Unfortunately did not get a way.

I am doing so because I can not use methods with <T> because of the structure of my application.

Melodymeloid answered 30/5, 2012 at 16:32 Comment(8)
"I am doing so because I can not use methods with "< T >" because of the structure of my application" -- Does that mean your NETFX version < 2.0? Why can't you use generics in your application?Fredra
Also, what does creating delegates for your properties have to do with reflection, and what problem are you trying to solve using reflection?Fredra
Delegates have vastly better performance and can be used dynamically. They are the preferred option when you need to use dynamic invocation.Electrolyse
@JoshE, clearly not < 2.0 since he is using generics and lambdas even. But I'm with you. What are you trying to do here ultimately?Columnar
Yes I can (.NET 4.0), but would not be good for all the logic of my application. And there would be many changes to make. Especially the communication between WebServices, there is no point in my application that applies "<T>" methods load, save, update, insert ...Melodymeloid
I'd suggest to use Fasterflect, a comprehensive library that makes reflection much faster and easier to use on top. See fasterflect.codeplex.com for details and usage. Built using DynamicMethod and IL generation with built-in caching.Picky
Or similar: FastMember - again, DynamicMethod / IL, with built-in cacheHandyman
Thanks for the suggestions, I was looking a little about libraries. But most require much implementation code and many changes in my application. If I still do not get adequate performance. I will behind...Melodymeloid
S
21

This should work for you:

static Action<object, object> BuildSetAccessor(MethodInfo method)
{
    var obj = Expression.Parameter(typeof(object), "o");
    var value = Expression.Parameter(typeof(object));

    Expression<Action<object, object>> expr =
        Expression.Lambda<Action<object, object>>(
            Expression.Call(
                Expression.Convert(obj, method.DeclaringType),
                method,
                Expression.Convert(value, method.GetParameters()[0].ParameterType)),
            obj,
            value);

    return expr.Compile();
}

Usage:

var accessor = BuildSetAccessor(typeof(TestClass).GetProperty("MyProperty").GetSetMethod());
var instance = new TestClass();
accessor(instance, "foo");
Console.WriteLine(instance.MyProperty);

With TestClass:

public class TestClass 
{
    public string MyProperty { get; set; }
}

Prints out:

foo

Saying answered 30/5, 2012 at 17:1 Comment(0)
R
21

I think you'd be better off with CreateDelegate construct if performance is the key. Since you know the signature of the method beforehand, which here is just GetGetMethod and GetSetMethod of the PropertyInfo, you can create a delegate to execute the very method with the same signature directly. Expressions would be better suited if you need to build some logic (for which you did not have a method handle) to delegates. I did some benchmarking on different routes to this problem:

Func<S, T> Getter;
Action<S, T> Setter;
PropertyInfo Property;
public void Initialize(Expression<Func<S, T>> propertySelector)
{
    var body = propertySelector.Body as MemberExpression;
    if (body == null)
        throw new MissingMemberException("something went wrong");

    Property = body.Member as PropertyInfo;



    //approaches:

    //Getter = s => (T)Property.GetValue(s, null);

    //Getter = memberSelector.Compile();

    //ParameterExpression inst = Expression.Parameter(typeof(S));
    //Getter = Expression.Lambda<Func<S, T>>(Expression.Property(inst, Property), inst).Compile();

    //var inst = Expression.Parameter(typeof(S));
    //Getter = Expression.Lambda<Func<S, T>>(Expression.Call(inst, Property.GetGetMethod()), inst).Compile();

    //Getter = (Func<S, T>)Delegate.CreateDelegate(typeof(Func<S, T>), Property.GetGetMethod());



    //Setter = (s, t) => Property.SetValue(s, t, null);

    //var val = Expression.Parameter(typeof(T));
    //var inst = Expression.Parameter(typeof(S));
    //Setter = Expression.Lambda<Action<S, T>>(Expression.Call(inst, Property.GetSetMethod(), val),
    //                                         inst, val).Compile();

    //Setter = (Action<S, T>)Delegate.CreateDelegate(typeof(Action<S, T>), Property.GetSetMethod());
}


//Actual calls (tested under loop):
public T Get(S instance)
{
    //direct invocation:
    //return (T)Property.GetValue(instance, null);

   //calling the delegate:
   //return Getter(instance);
}
public void Set(S instance, T value)
{
    //direct invocation:
    //Property.SetValue(instance, value, null);

   //calling the delegate:
   //Setter(instance, value);
}

Results for about 10000000 calls - (Get, Set):

GetValue-SetValue (direct): 3800 ms, 5500 ms

GetValue-SetValue (delegate): 3600 ms, 5300 ms

compiled expressions:

   Get: Expression.Property: 280 ms

        Expression.Call: 280 ms

        direct compile: 280 ms
   Set: 300 ms

create delegate: 130 ms, 135 ms

direct property call: 70 ms, 70 ms

I would, in your case, write:

public static Func<S, T> BuildGetAccessor<S, T>(Expression<Func<S, T>> propertySelector)
{
    return propertySelector.GetPropertyInfo().GetGetMethod().CreateDelegate<Func<S, T>>();
}

public static Action<S, T> BuildSetAccessor<S, T>(Expression<Func<S, T>> propertySelector)
{
    return propertySelector.GetPropertyInfo().GetSetMethod().CreateDelegate<Action<S, T>>();
}

// a generic extension for CreateDelegate
public static T CreateDelegate<T>(this MethodInfo method) where T : class
{
    return Delegate.CreateDelegate(typeof(T), method) as T;
}

public static PropertyInfo GetPropertyInfo<S, T>(this Expression<Func<S, T>> propertySelector)
{
    var body = propertySelector.Body as MemberExpression;
    if (body == null)
        throw new MissingMemberException("something went wrong");

    return body.Member as PropertyInfo;
}

So now you call:

TestClass cwp = new TestClass();
var access = BuildGetAccessor((TestClass t) => t.AnyValue);
var result = access(cwp);

Isn't that simpler?? Had written a generic class here to handle the exact thing.

Ridgepole answered 18/4, 2013 at 9:16 Comment(0)
E
1

Use dynamic types. They use reflection under the hood, but they're a lot faster.

Otherwise...

There are tons of free faster reflection libraries out there with permissive licenses. I would link you, but there are too many, and I'm not sure which would suit you. Just search codeplex etc. When you find something you like, try it out.

But yeah, maybe before that, think if reflection really is the answer. Often there are other solutions.

Edit: As Requested...

http://geekswithblogs.net/SunnyCoder/archive/2009/06/26/c-4.0-dynamics-vs.-reflection.aspx
http://theburningmonk.com/2010/09/performance-test-dynamic-method-invocation-in-csharp-4/
http://www.mssoftwareconsulting.com/msswc/blog/post/C-40-and-dynamic-performance.aspx

It's common knowledge as far as I can tell.

Electrolyse answered 30/5, 2012 at 16:47 Comment(7)
Dynamics should not be used for reflection, IMO, unless there is no other way. Can you post some data that supports they're a lot faster? ...and an example of using dynamics in a way the OP requests? These might be some of the reasons for the negative votes...Potentate
He's using dynamic invocation. E.g. setting methods, properties, etc. That's exactly what you're supposed to do with dynamics.Electrolyse
I understood dynamics to be e.g. dynamic foo = bar; Dynamics is a big topic - if you are referring to building ExpressionTree objects, then yes - that is what dynamics are for. :)Potentate
There is, as far as I know, only one thing in C# properly called a dynamic type, and that is what I meant. The DLR is designed for dynamic invocation of methods and properties. Apparently, something I didn't know until now, the DLR uses expression trees under the hood as well (besides reflection). If you check in the links above, you will see that invoking a method using a dynamic type is faster by several orders of magnitude than using MethodBase.Invoke. It's also a lot simpler and more concise than constructing an expression tree.Electrolyse
msdn.microsoft.com/en-us/magazine/cc163759.aspx delegate call was the most recommended....Melodymeloid
From the article: Parts of this article are based on a prerelease version of the .NET Framework 2.0. Those sections are subject to change. That is an obsolete article from long before dynamic even existed. However, I'm not disputing the fact that the DLR isn't the fastest way to invoke a method. I'm saying it's much faster than reflection, and ridiculously easy to use.Electrolyse
Agree with Greg ... Reflection is a big ugly hack - period. .. use only if there is no alternative .. C# 4 dynamic and InternalsVisableTo is better in most cases.Chondrule

© 2022 - 2024 — McMap. All rights reserved.