我正在尝试构建一个表达式,以根据数组中传递的值的顺序进行排序。我有大部分的概念,但我很困惑我如何选择表达式将三元组合在一起。
/// <summary>
/// This method will build an expression to map the order
/// of the ownerkeys to it's index to use for sorting
/// I.E I have an array [DivisionOwnerGuid, CompanyOwnerGuid]
/// ownerKey == {DivisionOwnerGuid} ? 0
/// ownerKey == {CompanyOwnerGuid} ? 1 : Int32.MaxValue
/// </summary>
protected Expression<Func<IConfigurationValue, int>> GetOrderByExpression(
guid[] ownerKeyByPriority)
{
// x =>
var parameter = Expression.Parameter(typeof(IConfigurationValue));
ownerKeyByPriority.Select((ownerKey, index) => new {
// Hack: Build the expressions using the same parameter
// to avoid having to use Expression Visitor
Condition = this.GetCondition(parameter, ownerKey),
Priority = index
}).Aggregate((accumulated, nextPriorityExpression) => {
// How can I aggregate the conditions together
Expression.Condition(nextPriorityExpression, nextPriorityExpression.Priority, )
});
}
protected BinaryExpression GetCondition(ParameterExpression parameter, guid ownerKey)
{
// x => x.OwnerGlobalIdRowKey
var property = Expression.Property(parameter,
nameof(IConfigurationValue.OwnerGlobalIdRowKey));
// x => x.OwnerGlobalIdRowKey == { valueOf(ownerKey) }
return Expression.Equal(property, Expression.Constant(ownerKey,
typeof(Guid)));
}
如何通过聚合函数继续传播三元链?
答案 0 :(得分:2)
忽略GetCondition
返回中的(潜在)类型错误,您可以通过正确的输入在Aggregate
中累积嵌套三元运算符的主体,然后构建一个lambda:
Expression<Func<IConfigurationValue, int>> GetOrderByExpression(
Guid[] ownerKeyByPriority) {
// x =>
var parameter = Expression.Parameter(typeof(IConfigurationValue));
var body = ownerKeyByPriority.Select((ownerKey, index) => new {
// Hack: Build the expressions using the same parameter
// to avoid having to use Expression Visitor
Test = this.GetCondition(parameter, ownerKey),
Priority = Expression.Constant(index)
}).Aggregate((Expression)Expression.Constant(int.MaxValue), (accumulated, nextPriorityExpression) =>
Expression.Condition(nextPriorityExpression.Test, nextPriorityExpression.Priority, accumulated)
);
return (Expression<Func<IConfigurationValue, int>>)Expression.Lambda(body, parameter);
}
答案 1 :(得分:0)
我最终写了一个可与属性和简单表达式一起使用的扩展方法
public static Expression<Func<TEntity, int>> GetOrderByArrayPriorityExpression<TEntity, TValue>(this Expression<Func<TEntity, TValue>> selectorExpression, TValue[] orderedValues)
{
var body = orderedValues.Select((value, index) => new {
//Note: Build the expressions using the same parameter to avoid having to use Expression Visitor
//x => x.Property == {value}
Condition = Expression.Equal(selectorExpression.Body, Expression.Constant(value, typeof(TValue))),
Priority = Expression.Constant(index)
}).Aggregate((Expression)Expression.Constant(int.MaxValue), (accumulated, nextPriorityExpression) =>
//This generates the conditions (in reverse which is also fine)
// x =>
// x.Property == {GlobalOwnerGuid} ? 3 :
// x.Property == {ClientOwnerGuid} ? 2 :
// x.Property == {CompanyOwnerGuid} ? 1 :
// x.Property == {DivisionOwnerGuid} ? 0 : Int.MaxValue
Expression.Condition(nextPriorityExpression.Condition, nextPriorityExpression.Priority, accumulated)
);
// reuse to original parameter to avoid using an expression visitor
return (Expression<Func<TEntity, int>>)Expression.Lambda(body, selectorExpression.Parameters);
}