将Func 强制转换为Func 的更快方法?

有没有更快的方法将FunFunc

 public static class StaticAccessors { public static Func TypedGetPropertyFn(PropertyInfo pi) { var mi = pi.GetGetMethod(); return (Func)Delegate.CreateDelegate(typeof(Func), mi); } public static Func ValueUnTypedGetPropertyTypeFn(PropertyInfo pi) { var mi = typeof(StaticAccessors).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? } } 

有没有办法将typedGetPropertyFn转换为Func而不像上面的例子那样在返回的lambda中有reflection代码?

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

好的,感谢280Z28让我沿着正确的道路走下去,我已经将其包含在下面的最终解决方案中。 我已将reflection代码留在那里,用于不支持表达式的平台。 对于这样做的平台来说,为了获得intstring属性,它会显示26x27x (13 / .5 ticks avg)的性能提升。

 public static Func ValueUnTypedGetPropertyTypeFn(PropertyInfo pi) { var mi = typeof(StaticAccessors).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> ( Expression.Convert( Expression.Call( Expression.Convert(obj, typedMi.DeclaringType), typedMi ), typeof(object) ), obj ); return expr.Compile(); #endif } 

如您所知,您可以从PropertyInfo.GetGetMethod()获取MethodInfo 。 从中,您可以使用以下命令获取Func以检索该属性。 通过类似的方法,您可以返回强类型的Func 。 对于任何给定的MethodInfo ,如果需要多次,则应该缓存此调用的结果,因为此方法比调用生成的委托至少要贵一个数量级。

 private static Func BuildAccessor(MethodInfo method) { ParameterExpression obj = Expression.Parameter(typeof(object), "obj"); Expression> expr = Expression.Lambda>( Expression.Convert( Expression.Call( Expression.Convert(obj, method.DeclaringType), method), typeof(object)), obj); return expr.Compile(); } 

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

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


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

 // copy and paste into LINQpad void Main() { Func func1 = GetString; string res1 = func1(1); res1.Dump(); Func func2 = func1; object res2 = func2(1); res2.Dump(); } public string GetString(T obj) { return obj.ToString(); } 

你考虑过做以下事情:

  Func typed = (f) => return new Bar(); Func untyped = (f) => typed(f); 

这样你就可以包装委托了。