如何附加到表达式

40 .net c# linq

根据我昨天提出的问题:

如果我必须附加到我现有的'where'表达式,我将如何追加?

Expression<Func<Client, bool>> clientWhere = c => true;

if (filterByClientFName)
{
    clientWhere = c => c.ClientFName == searchForClientFName;
}

 if (filterByClientLName)
    {
        clientWhere = c => c.ClientLName == searchForClientLName;
    }
Run Code Online (Sandbox Code Playgroud)

用户可以输入名字或姓氏或两者.如果他们同时输入我想附加到表达式.试着看看是否有相当于我可以做的追加

clientWhere.Append or clientWhere += add new expression
Run Code Online (Sandbox Code Playgroud)

或类似的东西

Jas*_*son 55

我相信你可以做到以下几点:

Expression<Func<Client, bool>> clientWhere = c => true;

if (filterByClientFName)
{
    var prefix = clientWhere.Compile();
    clientWhere = c => prefix(c) && c.ClientFName == searchForClientFName;
}
if (filterByClientLName)
{
    var prefix = clientWhere.Compile();
    clientWhere = c => prefix(c) && c.ClientLName == searchForClientLName;
}
Run Code Online (Sandbox Code Playgroud)

如果您需要将所有内容保存在Expression-land(与之一起使用IQueryable),您还可以执行以下操作:

Expression<Func<Client, bool>> clientWhere = c => true;

if (filterByClientFName)
{
    Expression<Func<Client, bool>> newPred = 
        c => c.ClientFName == searchForClientFName;
    clientWhere = Expression.Lambda<Func<Freight, bool>>(
        Expression.AndAlso(clientWhere, newPred), clientWhere.Parameters);
}
if (filterByClientLName)
{
    Expression<Func<Client, bool>> newPred = 
        c => c.ClientLName == searchForClientLName;
    clientWhere = Expression.Lambda<Func<Freight, bool>>(
        Expression.AndAlso(clientWhere, newPred), clientWhere.Parameters);
}
Run Code Online (Sandbox Code Playgroud)

通过定义此扩展方法,可以减少这种情况:

public static Expression<TDelegate> AndAlso<TDelegate>(this Expression<TDelegate> left, Expression<TDelegate> right)
{
    return Expression.Lambda<TDelegate>(Expression.AndAlso(left, right), left.Parameters);
}
Run Code Online (Sandbox Code Playgroud)

然后你可以使用这样的语法:

Expression<Func<Client, bool>> clientWhere = c => true;
if (filterByClientFName)
{
    clientWhere = clientWhere.AndAlso(c => c.ClientFName == searchForClientFName);
}
if (filterByClientLName)
{
    clientWhere = clientWhere.AndAlso(c => c.ClientLName == searchForClientLName);
}
Run Code Online (Sandbox Code Playgroud)

  • 杰森:学习每个人提供的所有信息.我试过你的方法,通过在静态类中定义扩展,我得到一个错误:二进制运算符AndAlso没有为类型'System.Func`2 [Models.Client,System.Boolean]'和'System定义. Func`2 [Models.Client,System.Boolean]". (5认同)
  • 即使您在扩展方法中修复了错误,这也是一种非常脆弱的方法.有关详细信息,请参阅我对http://stackoverflow.com/questions/2231302/append-to-an-expression-c的回答. (4认同)
  • @Jason:在我看来,显示名称为“Jason”的用户太多了。 (2认同)

Jos*_*dan 12

这是一个复杂的场景.您几乎在LINQ之上构建自己的查询引擎.JaredPar的解决方案(它去了哪里?)如果你想要在所有标准之间进行逻辑AND,那就太棒了,但情况可能并非总是如此.

当我最近在我的一个项目中与此争吵时,我创建了两个列表:

List<Predicate<T>> andCriteria;
List<Predicate<T>> orCriteria;
Run Code Online (Sandbox Code Playgroud)

(在这种情况下,T是客户,为您服务)

我会在列表中填充我想要成为真实的谓词.例如,

decimal salRequirement = 50000.00;
andCriteria.Add(c => c.Salary > salRequirement);
orCriteria.Add(c => c.IsMarried);
Run Code Online (Sandbox Code Playgroud)

然后,我将检查我的Where子句中的列表中的所有条件.例如:

Expression<Func<Client, bool>> clientWhere =
    c => andCriteria.All(pred => pred(c) ) && orCriteria.Any(pred => pred(c) );
Run Code Online (Sandbox Code Playgroud)

出于可读性的考虑,这也可以通过for循环完成.在应用OR和AND子句时,请记住使用正确的操作顺序.


tru*_*oda 9

如果您遇到类似的问题,您可以在这个伟大的主题中找到所有可能的解决方案。或者只是使用 PredicateBuilder 是这个 poporse 的好帮手。

var predicate = PredicateBuilder.True<Client>();

if (filterByClientFName)
{
    predicate = predicate.And(c => c.ClientFName == searchForClientFName);
}

if (filterByClientLName)
{
        predicate = predicate.And(c => c.ClientLName == searchForClientLName);
}

var result = context.Clients.Where(predicate).ToArray();
Run Code Online (Sandbox Code Playgroud)

这是一些构建器实现。

public static class PredicateBuilder
    {
        // Creates a predicate that evaluates to true.        
        public static Expression<Func<T, bool>> True<T>() { return param => true; }

        // Creates a predicate that evaluates to false.        
        public static Expression<Func<T, bool>> False<T>() { return param => false; }

        // Creates a predicate expression from the specified lambda expression.        
        public static Expression<Func<T, bool>> Create<T>(Expression<Func<T, bool>> predicate) { return predicate; }

        // Combines the first predicate with the second using the logical "and".        
        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        {
            return first.Compose(second, Expression.AndAlso);
        }

        // Combines the first predicate with the second using the logical "or".        
        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        {
            return first.Compose(second, Expression.OrElse);
        }

        // Negates the predicate.        
        public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> expression)
        {
            var negated = Expression.Not(expression.Body);
            return Expression.Lambda<Func<T, bool>>(negated, expression.Parameters);
        }

        // Combines the first expression with the second using the specified merge function.        
        static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
        {
            // zip parameters (map from parameters of second to parameters of first)
            var map = first.Parameters
                .Select((f, i) => new { f, s = second.Parameters[i] })
                .ToDictionary(p => p.s, p => p.f);

            // replace parameters in the second lambda expression with the parameters in the first
            var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);

            // create a merged lambda expression with parameters from the first expression
            return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
        }

        class ParameterRebinder : ExpressionVisitor
        {
            readonly Dictionary<ParameterExpression, ParameterExpression> map;

            ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
            {
                this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
            }

            public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
            {
                return new ParameterRebinder(map).Visit(exp);
            }

            protected override Expression VisitParameter(ParameterExpression p)
            {
                ParameterExpression replacement;
                if (map.TryGetValue(p, out replacement))
                {
                    p = replacement;
                }
                return base.VisitParameter(p);
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)


Vas*_*nan 6

看看Predicate Builder,我相信这可能适合你.