Reflection Performance - Create Delegate (Properties C#)
Solution 1
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
Solution 2
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.
Solution 3
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.
Related videos on Youtube
J. Lennon
Updated on June 07, 2022Comments
-
J. Lennon almost 2 years
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.-
Josh E almost 12 years"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?
-
Josh E almost 12 yearsAlso, what does creating delegates for your properties have to do with reflection, and what problem are you trying to solve using reflection?
-
GregRos almost 12 yearsDelegates have vastly better performance and can be used dynamically. They are the preferred option when you need to use dynamic invocation.
-
aquinas almost 12 years@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?
-
J. Lennon almost 12 yearsYes 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 ...
-
Morten Mertner almost 12 yearsI'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.
-
Marc Gravell almost 12 yearsOr similar: FastMember - again, DynamicMethod / IL, with built-in cache
-
J. Lennon almost 12 yearsThanks 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...
-
-
IAbstract almost 12 yearsDynamics 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...
-
GregRos almost 12 yearsHe's using dynamic invocation. E.g. setting methods, properties, etc. That's exactly what you're supposed to do with dynamics.
-
IAbstract almost 12 yearsI understood dynamics to be e.g.
dynamic foo = bar;
Dynamics is a big topic - if you are referring to buildingExpressionTree
objects, then yes - that is what dynamics are for. :) -
GregRos almost 12 yearsThere 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. -
J. Lennon almost 12 yearsmsdn.microsoft.com/en-us/magazine/cc163759.aspx delegate call was the most recommended....
-
GregRos almost 12 yearsFrom 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. -
user1496062 about 10 yearsAgree 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.