如何汇总功能表达式

问题描述 投票:0回答:1

是否可以通过快捷方式将此代码

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()

以一种方式,我具有一个带有Exphere子句的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个回答
0
投票

表达式基本上是内存中的代码表示形式,因此绝对有可能。

示例代码:

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);
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.