C# 从返回字典的 GroupBy 中选择 Expr
本文关键字:选择 Expr GroupBy 返回 字典 | 更新日期: 2023-09-27 18:33:43
Using Net 4.5.1, C#....
使用 IQueryable,我有一个返回字典的 GroupBy 子句。 这是通过以下代码完成的:
public static Expression<Func<ChartJoin, Dictionary<string, object>>> GetGroupByDictionary(NameValueCollection fields)
{
var parameter = Expression.Parameter(typeof(ChartJoin));
var addMethod = typeof(Dictionary<string, object>)
.GetMethod(
"Add",
new[] { typeof(string), typeof(object) }
);
var selector = Expression.ListInit(
Expression.New(typeof(Dictionary<string, object>)),
fields.AllKeys.Select(
key => Expression.ElementInit(
addMethod,
Expression.Constant(key),
Expression.Convert(
Chart.getNestedPropertyOrField(parameter, fields[key]), // basically drills down to a nested property (note: static method not shown to save space)
typeof(object)
)
)
)
);
var lambda = Expression.Lambda<Func<ChartJoin, Dictionary<string, object>>>(selector, parameter);
return lambda;
}
然后调用是:
NameValueCollection fields = new NameValueCollection();
fields.Add("Year", "Respondent.currentVisitYear");
fields.Add("Month", "Respondent.currentVisitMonth");
// .... could be more fields
<some IQueryable<ChartJoin>
.GroupBy(
Chart.GetGroupByDictionary(fields).Compile(),
new DictionaryComparer<string, object>()
);
DictionaryComparer允许唯一性,提供Equals和GetHashCode实现。 我想返回一个带有 Select 子句的字典。 尝试一个简单的示例,选择一个 GroupBy 键(例如 Select(GetKey("Year")。编译())):
private static Expression<Func<IGrouping<IDictionary<string, object>, ChartJoin>, Dictionary<string, object>>> GetKey(String key)
{
var block = ? /// Need logic to get a the IGrouping.Key property and pull the value
var addMethod = typeof(Dictionary<string, object>)
.GetMethod(
"Add",
new[] { typeof(string), typeof(object) }
);
var selector = Expression.ListInit(
Expression.New(typeof(Dictionary<string, object>)),
Expression.ElementInit(
addMethod,
Expression.Constant(key),
Expression.Convert(
block,
typeof(object)
)
)
);
var lambda = Expression.Lambda<Func<IGrouping<IDictionary<string, object>, ChartJoin>, Dictionary<string, object>>>(selector, parameter);
return lambda;
}
如果有人能让我从上述内容开始(即如何创建块表达式以从 GroupBy.Key 中提取字典值),那就太好了。
回答我自己的问题,因为注释对于代码来说太浅了。
基本上,为Select编写表达式并不是经过一些实验的火箭科学。 例如,下面是将组键拉入选择的代码:
private static Expression<Func<IGrouping<IDictionary<string, object>, Respondent>, IDictionary<string, object>>> GetKey(String field)
{
// x =>
var ParameterType = typeof(IGrouping<IDictionary<string, object>, Respondent>);
var parameter = Expression.Parameter(ParameterType, "x");
// x => x.Key
var Key = Expression.Property(parameter, "Key");
// x => x.Key[field]
Expression KeyExpression = Expression.Property(Key, "Item", new Expression[] { Expression.Constant(field) });
ParameterExpression KeyResult = Expression.Parameter(typeof(object));
BlockExpression block = Expression.Block(
new[] { KeyResult },
Expression.Assign(KeyResult, KeyExpression),
KeyResult
);
.... // <- the block is put in the selector (as shown above)
}
当我开始考虑静态方法调用时,对 GroupBy 进行计数也很简单:
// x => x.Count()
MethodInfo CountMethod = (typeof(Enumerable))
.GetMethods()
.First(
method => method.Name == "Count"
&& method.IsGenericMethod
)
.MakeGenericMethod(typeof(Respondent));
Expression CountExpression = Expression.Call(null, CountMethod, parameter);
Sum也很有趣:
// x => x.Sum(m => m.MWEIGHT) where MWEIGHT is a ?decimal (i.e. nullable)
var m = Expression.Parameter(typeof(Respondent), "m");
PropertyInfo SumPropertyInfo = typeof(Respondent).GetProperty("MWEIGHT");
Expression SumSelector = Expression.Lambda(
Expression.Convert(Expression.MakeMemberAccess(m, SumPropertyInfo), typeof(decimal)),
m
);
MethodInfo SumMethod = (typeof(Enumerable))
.GetMethods()
.First(
method => method.Name == "Sum"
&& method.ReturnType == typeof(decimal)
&& method.IsGenericMethod
)
.MakeGenericMethod(typeof(Respondent));
Expression SumExpression = Expression.Call(null, SumMethod, parameter, SumSelector);