将Func 强制转换为Func 的更快方法?
有没有更快的方法将Fun
为Func
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代码留在那里,用于不支持表达式的平台。 对于这样做的平台来说,为了获得int
和string
属性,它会显示26x到27x (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
在.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);
这样你就可以包装委托了。