Faster way to cast a Func<T, T2> to Func<T, object>?

c#, covariance, lambda, reflection

Solution

As you know, you can obtain a `MethodInfo` from `PropertyInfo.GetGetMethod()`. From that, you can use the following to get a `Func<object, object>` to retrieve that property. By a similar method, you could return a strongly-typed `Func<TObject, TResult>`. For any given `MethodInfo`, 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.

private static Func<object, object> BuildAccessor(MethodInfo method)
{
    ParameterExpression obj = Expression.Parameter(typeof(object), "obj");

    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();
}

Problem

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 } ```

Original source

Related problems