更快地转换 Func的方法到 Func?
是否有更快的方法将 Fun
转换为 Func
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?
}
}
有没有办法将 typedGetPropertyFn
转换为Func
在返回的 lambda 中没有反射代码(如上面的示例所示)?
编辑:添加修改后的解决方案
好的,感谢 280Z28 引导我走上正确的道路,我已将其包含在下面的最终解决方案中。对于不支持表达式的平台,我将反射代码留在了那里。对于这样做的平台,获取 int
和 string< 的性能提升为 26x 到 27x(平均 13 / .5 个刻度) /代码> 属性。
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
}
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
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您是否考虑过执行以下操作:
这样您只需包装委托即可。
Have you considered doing the following:
This way you just wrap the delegate.
如您所知,您可以从
PropertyInfo.GetGetMethod()
获取MethodInfo
。由此,您可以使用以下代码获取Func
来检索该属性。通过类似的方法,您可以返回强类型Func
。对于任何给定的 MethodInfo,如果多次需要此调用的结果,则应缓存此调用的结果,因为此方法比调用结果委托至少要昂贵一个数量级。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.在 .NET 4.0 中,您可以执行此操作,因为 Func 委托使用 out 修饰符标记 TResult。 .NET 3.5 不支持通用协方差/逆变所以你不能简单地投射。我不确定是否还有另一种比反射更快的聪明方法。
这是Func 的 .NET 4.0 文档页面。请注意,TResult 被标记为“out”,因此它的返回值可以转换为不太特定的类型,例如对象。
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.
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.