按键字段将第二个组添加到现有Lambda表达式

时间:2013-09-04 18:12:56

标签: c# linq lambda dynamic-linq

我有一个表达式,我动态创建用于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”,我该如何将它添加到现有表达式中?

1 个答案:

答案 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();
}