表达式.呼叫组此时选择
本文关键字:选择 呼叫 表达式 | 更新日期: 2023-09-27 18:05:23
我试图使用表达式树来构建嵌套的组对,并且完全被Select和它对参数的期望所难倒。我最终想做的是通过表达式树来构建这个;
var queryNestedGroups = products.GroupBy(x => x.Category)
.Select(p => new
{
key = p.Key,
objects = p.ToList().GroupBy(y => y.Subcategory)
.Select(y => new { key = y.Key, objects = y.ToList() })
})
.AsQueryable();
这是我目前为止的尝试(产品是一个列表);
var data = Expression.Constant(products);
var arg = Expression.Parameter(typeof(Product), "arg");
var nameProperty = Expression.PropertyOrField(arg, "Category");
var groupByLambda = Expression.Lambda<Func<Product, string>>(nameProperty, arg);
var groupByExpression = Expression.Call(
typeof(Queryable),
"GroupBy",
new Type[] { typeof(Product), typeof(string) },
data,
groupByLambda);
var parameterExp = Expression.Parameter(typeof(IGrouping<string, Product>), "p");
var keyProp = Expression.PropertyOrField(parameterExp, "Key");
ConstructorInfo constructorInfo = typeof(object)
.GetConstructor(new[] { typeof(string), typeof(Product) });
Type anonymousResultType = new { Key = "abc", Values = new List<Product>() }.GetType();
var exp = Expression.New(
anonymousResultType.GetConstructor(new[] { typeof(string), typeof(List<Product>) }),
Expression.Constant("def"),
Expression.Constant(new List<Product>()));
var selectLambda = Expression.Lambda(exp);
var selectExpression = Expression.Call(
typeof(Queryable),
"Select",
new Type[] { typeof(List<Product>), selectLambda.Body.Type },
data,
selectLambda);
var finalExpression = Expression.Lambda(groupByExpression);
一切都很顺利,除了我得到异常var selectExpression =…告诉我类型参数和参数是错误的。不幸的是,它没有告诉我哪些参数以及为什么它们是错误的。我已经试过了所有我能想到的排列。两个问题;
我怎么知道
- 它想要的类型是什么?
- 在这种情况下,正确的类型/参数是什么?
下面是您想要做的代码。每个选择都需要在表达式树中有自己的lambda投影。你也有两个不同的匿名类型,一个是内部匿名类型的IEnumerable,一个是产品列表。
也因为它是链接到对象,你不需要Queryable你可以只使用Enumerable和p.ToList()。GroupBy(y => y. subcategory)列表是不需要的,所以我没有转换它
如果不使用匿名类型而使用具体类,也会更简单。尤其是在最后。因为它不能是强类型的,你只需要编译它,然后动态调用它。
// This could be a parameter
var data = Expression.Constant(products);
var outterGroupByarg = Expression.Parameter(typeof(Product), "x");
var outterGroupNameProperty = Expression.PropertyOrField(outterGroupByarg, "Category");
var outterGroupByLambda = Expression.Lambda<Func<Product, string>>(outterGroupNameProperty, outterGroupByarg);
var outterGroupByExpression = Expression.Call(typeof(Enumerable), "GroupBy", new [] { typeof(Product), typeof(string) },
data, outterGroupByLambda);
var outterSelectParam = Expression.Parameter(typeof (IGrouping<string, Product>), "p");
var innerGroupByarg = Expression.Parameter(typeof(Product), "y");
var innerGroupNameProperty = Expression.PropertyOrField(innerGroupByarg, "Subcategory");
var innerGroupByLambda = Expression.Lambda<Func<Product, string>>(innerGroupNameProperty, innerGroupByarg);
var innerGroupByExpression = Expression.Call(typeof(Enumerable), "GroupBy", new[] { typeof(Product), typeof(string) },
outterSelectParam, innerGroupByLambda);
var innerAnonymousType = new {Key = "abc", objects = new List<Product>()};
var innerSelectProjectionarg = Expression.Parameter(typeof(IGrouping<string, Product>), "y");
var innerKeyProp = Expression.Property(innerSelectProjectionarg, "Key");
var innerToList = Expression.Call(typeof (Enumerable), "ToList", new[] {typeof (Product)},
innerSelectProjectionarg);
var innerAnonymousResultType = innerAnonymousType.GetType();
var innerAnonymousConstructor =
innerAnonymousResultType.GetConstructor(new[] {typeof (string), typeof (List<Product>)});
var innerAnonymous = Expression.New(innerAnonymousConstructor, innerKeyProp, innerToList);
var innerSelectProjection =
Expression.Lambda(typeof(Func<,>).MakeGenericType(typeof(IGrouping<string, Product>), innerAnonymousResultType), innerAnonymous,
innerSelectProjectionarg);
var innerSelectExpression = Expression.Call(typeof(Enumerable), "Select", new [] { typeof(IGrouping<string, Product>), innerAnonymousResultType },
innerGroupByExpression, innerSelectProjection);
var outterAnonymousType = new {Key = "abc", Values = new[] {innerAnonymousType}.AsEnumerable()};
var outterAnonymousResultType = outterAnonymousType.GetType();
var outterAnonymousConstructor =
outterAnonymousResultType.GetConstructor(new[] { typeof(string), typeof(IEnumerable<>).MakeGenericType(innerAnonymousResultType) });
var outterKeyProp = Expression.PropertyOrField(outterSelectParam, "Key");
var outterAnonymous = Expression.New(outterAnonymousConstructor, outterKeyProp, innerSelectExpression);
var outterSelectProjection =
Expression.Lambda(
typeof (Func<,>).MakeGenericType(typeof (IGrouping<string, Product>), outterAnonymousResultType),
outterAnonymous,
outterSelectParam);
var outterSelect = Expression.Call(typeof(Enumerable), "Select", new[] { typeof(IGrouping<string, Product>), outterAnonymousResultType },
outterGroupByExpression, outterSelectProjection);
// Lamda is a func with no input because list of products was set as a constant and not a parameter
var finial =
Expression.Lambda(
typeof (Func<>).MakeGenericType(typeof (IEnumerable<>).MakeGenericType(outterAnonymousResultType)),
outterSelect);