我有一个表达式,我动态创建用于LINQ查询。目前,为了构造表达式,我使用以下代码:
var arg = Expression.Parameter(typeof(T), helper.getName());
var prop = Expression.Property(arg, "customerType");
var body = Expression.Convert(prop, typeof(object));
var lambda = Expression.Lambda<Func<Contact, object>>(body, arg);
var keySelector = lambda.Compile();
然后我使用GroupBy中的keySelector进行LINQ查询。我的问题是,如果我想在这个表达式中添加第二个分组标准,比如说“salesStage”,我该如何将它添加到现有表达式中?
答案 0 :(得分:0)
您遇到了问题,因为编译器在常规GroupBy
调用上执行的操作是生成具有您定义的属性的新匿名类型。如果类型不存在,我们就无法创建一个创建该类型对象的表达式。
但是,鉴于您将此用于LINQ-to-Objects,我们可以使用Tuple<>
类型生成分组键。希望您不需要对超过8个参数进行分组。
以下是生成分组功能的通用函数:
static Func<T, object> BuildGrouper<T>(IEnumerable<string> properties) {
var arg = Expression.Parameter(typeof(T), helper.getName());
// This is the list of property accesses we will be using
var parameters = properties.Select(propName => Expression.Property(arg, propName)).ToList();
// Find the correct overload of Tuple.Create.
// This will throw if the number of parameters is more than 8!
var method = typeof(Tuple).GetMethods().Where(m => m.Name == "Create" && m.GetParameters().Length == parameters.Count).Single();
// But it is a generic method, we need to specify the types of each of the arguments
var paramTypes = parameters.Select(p => p.Type).ToArray();
method = method.MakeGenericMethod(paramTypes);
// Invoke the Tuple.Create method and return the Func
var call = Expression.Call(null, method, parameters);
var lambda = Expression.Lambda<Func<T, object>>(call, arg);
return lambda.Compile();
}