将Func <T,T2>强制转换为Func <T,object>的更快方法?

myt*_*thz 17 c# reflection lambda covariance

是否有投一个更快的方法Fun<TEntity, TId>来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?
 }
}
Run Code Online (Sandbox Code Playgroud)

有没有办法在返回的lambda中转换typedGetPropertyFn为Func<TEntity, object>没有反射代码,如上例所示?

编辑:添加修改后的解决方案

好的,感谢280Z28引导我沿着正确的道路前进,我已经将其包含在下面的最终解决方案中.我已将反射代码留在那里,用于不支持表达式的平台.对于这样做的平台来说,它可以获得26x到27x(13/.5 ticks avg)的性能提升int和string性能.

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
}
Run Code Online (Sandbox Code Playgroud)

Sam*_*ell 8

如你所知,你可以得到一个MethodInfo从PropertyInfo.GetGetMethod().从那里,您可以使用以下内容Func<object, object>来获取该属性.通过类似的方法,您可以返回强类型Func<TObject, TResult>.对于任何给定的MethodInfo,如果您需要多次,则应该缓存此调用的结果,因为此方法比调用生成的委托至少要贵一个数量级.

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();
}
Run Code Online (Sandbox Code Playgroud)


jon*_*nii 8

你考虑过做以下事情:

 Func<Foo, Bar> typed = (f) => return new Bar();
 Func<Foo, object> untyped = (f) => typed(f);
Run Code Online (Sandbox Code Playgroud)

这样你只需包装代理.

  • 如果您在编译时使用了“ Bar”类型,则这将是执行此XD的最简单,最“奥林匹克”的方式。 (2认同)

Jos*_*osh 5

在.NET 4.0中,您可以这样做,因为Func委托使用out修饰符标记TResult..NET 3.5不支持通用协方差/逆变,因此您不能简单地进行转换.我不确定是否还有另一种聪明的方法,它比反射更快.

这是Func的.NET 4.0 doc页面.请注意,TResult标记为"out",因此其返回值可以转换为特定于较小的类型(如object).


对于没有外部依赖关系的快速示例,以下代码无法在.NET 3.5上编译,但在.NET 4.0上编译并正确运行.

// copy and paste into LINQpad
void Main()
{
    Func<int, string> func1 = GetString;
    string res1 = func1(1);
    res1.Dump();

    Func<int, object> func2 = func1;
    object res2 = func2(1);
    res2.Dump();
}

public string GetString<T>(T obj) {
    return obj.ToString();
}
Run Code Online (Sandbox Code Playgroud)