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)
如你所知,你可以得到一个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)
你考虑过做以下事情:
Func<Foo, Bar> typed = (f) => return new Bar();
Func<Foo, object> untyped = (f) => typed(f);
Run Code Online (Sandbox Code Playgroud)
这样你只需包装代理.
在.NET 4.0中,您可以这样做,因为Func委托使用out修饰符标记TResult..NET 3.5不支持通用协方差/逆变,因此您不能简单地进行转换.我不确定是否还有另一种聪明的方法,它比反射更快.
这是Func的.NET 4.0 doc页面.请注意,TResult标记为"out",因此其返回值可以转换为特定于较小的类型(如object).
// 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)
| 归档时间: |
|
| 查看次数: |
9686 次 |
| 最近记录: |