This question already has an answer here:
Is there a faster way to cast Fun<TEntity, TId>
to Func<TEntity, object>
public static class StaticAccessors<TEntity>
{
public static Func<TEntity, TId> TypedGetPropertyFn<TId>(PropertyInfo pi)
{
var mi = pi.GetGetMethod();
return (Func<TEntity, TId>)Delegate.CreateDelegate(typeof(Func<TEntity, TId>), mi);
}
public static Func<TEntity, object> ValueUnTypedGetPropertyTypeFn(PropertyInfo pi)
{
var mi = typeof(StaticAccessors<TEntity>).GetMethod("TypedGetPropertyFn");
var genericMi = mi.MakeGenericMethod(pi.PropertyType);
var typedGetPropertyFn = (Delegate)genericMi.Invoke(null, new[] { pi });
//slow: lambda includes a reflection call
return x => typedGetPropertyFn.Method.Invoke(x, new object[] { }); //can we replace this?
}
}
Is there a way to convert typedGetPropertyFn
to a Func<TEntity, object>
without having reflection code in the returned lambda like the example above?
EDIT: added modified solution
Ok thanks to 280Z28 for leading me down the right path which I've included in the final solution below. I've left the reflection code in there for platforms that don't support Expressions. For platforms that do it's showing a 26x to 27x (13 / .5 ticks avg) perf increase for getting int
and string
properties.
public static Func<TEntity, object> ValueUnTypedGetPropertyTypeFn(PropertyInfo pi)
{
var mi = typeof(StaticAccessors<TEntity>).GetMethod("TypedGetPropertyFn");
var genericMi = mi.MakeGenericMethod(pi.PropertyType);
var typedGetPropertyFn = (Delegate)genericMi.Invoke(null, new[] { pi });
#if NO_EXPRESSIONS
return x => typedGetPropertyFn.Method.Invoke(x, new object[] { });
#else
var typedMi = typedGetPropertyFn.Method;
var obj = Expression.Parameter(typeof(object), "oFunc");
var expr = Expression.Lambda<Func<TEntity, object>> (
Expression.Convert(
Expression.Call(
Expression.Convert(obj, typedMi.DeclaringType),
typedMi
),
typeof(object)
),
obj
);
return expr.Compile();
#endif
}
Have you considered doing the following:
This way you just wrap the delegate.
As you know, you can obtain a
MethodInfo
fromPropertyInfo.GetGetMethod()
. From that, you can use the following to get aFunc<object, object>
to retrieve that property. By a similar method, you could return a strongly-typedFunc<TObject, TResult>
. For any givenMethodInfo
, you should cache the results of this call if you need it more than once since this method is at least an order of magnitude more expensive than calling the resulting delegate.In .NET 4.0 you can do this because the Func delegate marks TResult with the out modifier. .NET 3.5 does not support generic covariance/contravariance so you can't simply cast. I'm not sure if there's another clever way of doing it that is faster than reflection.
Here's the .NET 4.0 doc page for Func. Notice that TResult is marked with "out" so its return value can be cast as a less-specific type such as object.
For a quick example that has no external dependencies, the following code fails to compile on .NET 3.5 but compiles and runs correctly on .NET 4.0.