我正在尝试调整下面的代码来构建泛型函数,该函数返回聚合函数的表达式,例如sum,count average,min,max for data list
总和正在运作,但其他人则没有。我有附加信息:参数数量不正确异常。是的,显然是Expression.Call为其他人构建错误,但找不到任何doc如何为其他聚合函数构建正确的表达式。
public Expression AggregateFunc(IQueryable source, string member, string aggFunc)
{
// Properties
PropertyInfo property = source.ElementType.GetProperty(member);
FieldInfo field = source.ElementType.GetField(member);
ParameterExpression parameter = Expression.Parameter(source.ElementType, "f");
Expression selector = Expression.Lambda(Expression.MakeMemberAccess(parameter, (MemberInfo)property ?? field), parameter);
// Method
var l = typeof(Queryable).GetMethods().Where(m => m.Name == aggFunc).ToList();
MethodInfo method = typeof(Queryable).GetMethods().First(m => m.Name == aggFunc );
return Expression.Call(
null,
method.MakeGenericMethod(new[] { source.ElementType }),
new[] { source.Expression, Expression.Quote(selector) });
}
用法:
var list = new List<Int32FormFieldData>()
{
new FormFieldData { Path = "1", Value = 1 },
new FormFieldData { Path = "2", Value = 2 },
new FormFieldData { Path = "3", Value = 3 }
};`
AggregateFunc(list.AsQueryable(), "Value", "Count");
答案 0 :(得分:1)
要使其适用于Min,Max等,您需要进行一些更改(请参阅注释):
public static Expression AggregateFunc(IQueryable source, string member, string aggFunc) {
PropertyInfo property = source.ElementType.GetProperty(member);
FieldInfo field = source.ElementType.GetField(member);
ParameterExpression parameter = Expression.Parameter(source.ElementType, "f");
Expression selector = Expression.Lambda(Expression.MakeMemberAccess(parameter, (MemberInfo) property ?? field), parameter);
// Method
// find correct method with two parameters: IQueryable and selector
MethodInfo method = typeof(Queryable).GetMethods().Where(c => c.GetParameters().Length == 2).First(m => m.Name == aggFunc);
// some aggregates have two generic type arguments (such as min, max, average)
// others like Sum have just one
var genArgs = new List<Type>();
genArgs.Add(source.ElementType);
if (method.GetGenericArguments().Length > 1) {
genArgs.Add(property?.PropertyType ?? field.FieldType);
}
return Expression.Call(
null,
method.MakeGenericMethod(genArgs.ToArray()),
new[] {source.Expression, Expression.Quote(selector)});
}
然而,Count是不同的,因为对于它来说,选择器没有任何意义(你不会调用Count(c => c.Value)
),所以为此最好创建具有不同签名的单独方法(没有member
)。