【问题标题】:How to aggregate Functional Expression from a variable set of expressions如何从一组变量表达式聚合函数表达式
【发布时间】:2019-09-25 12:17:20
【问题描述】:

有没有办法缩短这段代码

Expression<Func<MyType, bool>> a => t => ...;
Expression<Func<MyType, bool>> b => t => ...;
Expression<Func<MyType, bool>> c => t => ...;

await myIQueryableOfMyType
  .Where(a)
  .Where(b)
  .Where(c)
  .ToArrayAsync()

在某种程度上,我有一个带有 Single Where 子句的单一 Experssion。 我的目的是将“a”、“b”、“c”表达式替换为可变条件集。

我尝试聚合一个函数并将其设置在新的 Lambda 表达式中

Expression<Func<MyType, bool>>[] predicates = ...

Func<MyType, bool> func = t => predicates == null || predicates.Aggregate(true, (prev, current) => prev && current.Compile()(t));

但它不适用于实体框架的 IQueryable 集合

【问题讨论】:

标签: c# entity-framework lambda expression


【解决方案1】:

表达式基本上是内存中的代码表示,所以肯定是可以的。

示例代码:

static void Main(string[] args)
{
    Expression<Func<MyType, bool>> a = t => t.Id == 1;
    Expression<Func<MyType, bool>> b = t => t.Name == "Name1";
    Expression<Func<MyType, bool>> c = t => t.Desc == "Desc1";

    Expression<Func<MyType, bool>> combined = LinqExtensions.And(a, b, c);

    await myIQueryableOfMyType
        .Where(combined)
        .ToArrayAsync()
}

public static class LinqExtensions
{
    // Combine array of predicates into one
    // For example for input:
    //    [ t1 => t1.Id == 1, t2 => t2.Name == "Name1", t3 => t3.Desc == "Desc1" ]
    // output will be
    //    p => p.Id == 1 && p.Name == "Name1" && p.Desc == "Desc1"
    public static Expression<Func<T, bool>> And<T>(params Expression<Func<T, bool>>[] predicates)
    {
        // this is `p`
        ParameterExpression param = Expression.Parameter(typeof(T));
        Expression body = null;

        foreach (Expression<Func<T, bool>> predicate in predicates)
        {
            body = body == null
                // first expression, just assign it to body
                ? predicate.Body
                // join body with predicate using &&
                : Expression.AndAlso(body, predicate.Body);
        }

        // Create lambda
        return Expression.Lambda<Func<T, bool>>(
            // this is where we replace t1, t2, t3 with p
            new ParamExpressionVisitor(param).Visit(body),
            param
        );
    }

    private class ParamExpressionVisitor : ExpressionVisitor
    {
        private ParameterExpression _parameter;

        public ParamExpressionVisitor(ParameterExpression parameter)
        {
            this._parameter = parameter;
        }

        protected override Expression VisitParameter(ParameterExpression node)
        {
            if (node.Type == this._parameter.Type)
            {
                return this._parameter;
            }

            return base.VisitParameter(node);
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多