【问题标题】:Apply Where conditionally (OR between them) LINQ有条件地应用Where(或它们之间)LINQ
【发布时间】:2016-09-03 18:38:32
【问题描述】:

我的 asp.net 项目中有过滤器,并希望将表达式添加到此列表中,条件为:

Expression<Func<MyModel, bool>> func;
var list = new List<Expression<Func<MyModel, bool>>>();

我想有条件地应用 Where(它们之间的 OR)。例如:

if(sth){
   func = p => p.a <= b;
   list.Add(func);
}
if (sth else){
   func = p => p.c >= d;
   list.Add(func);
}

var fq = Session.Query<MyModel>();
fq = list.Aggregate(fq, (current, expression) => current.Where(expression));

我该怎么做?

【问题讨论】:

  • 你现在拥有的有什么问题?您尚未显示 MyModel 类 (?) 的内容,但将其替换为 int 即可。
  • 编辑过的帖子,也许你能帮我:(@decPL顺便说一下我是c#的菜鸟
  • 我没有得到你想要做的事情??

标签: c# linq functional-programming conditional


【解决方案1】:

看起来您可以使用扩展方法轻松做到这一点

public static class EnumerableExtensions
{
    public static IEnumerable<T> ConditionalWhere<T>(this IEnumerable<T> list, 
                                               bool condition, Func<T,bool> predicate)
    {
        if(!condition)
             return list;
        return list.Where(predicate);
    }
}

用法如下:

var fq = Session.Query<MyModel>();
var result = fq.ConditionalWhere(sth, p => p.a <= b)
               .ConditionalWhere(sth_else, p => p.c >= d);

【讨论】:

  • @fsacer - 它确实有效,因为 OP 并不真正想要 OR 条件,因此 - 他们希望有条件地应用基于布尔值的 Where 子句。这只是简化了一点(但那是 DV,甚至没有理解答案!)
  • @fsacer 这个问题从一开始就不清楚,你必须承认这一点。
【解决方案2】:

您可以使用OR 关系构建一个扩展方法来合并两个条件表达式,如下所示:

public static class Extensions
{
    public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> one, Expression<Func<T, bool>> another)
    {
        var parameter = one.Parameters[0];
        var visitor = new ReplaceParameterVisitor(parameter);
        another = (Expression<Func<T, bool>>)visitor.Visit(another);
        var body = Expression.Or(one.Body, another.Body);
        return Expression.Lambda<Func<T, bool>>(body, parameter);
    }
}

class ReplaceParameterVisitor : ExpressionVisitor
{
    public ParameterExpression NewParameter { get; private set; }

    public ReplaceParameterVisitor(ParameterExpression newParameter)
    {
        this.NewParameter = newParameter;
    }

    protected override Expression VisitParameter(ParameterExpression node)
    {
        return this.NewParameter;
    }
}

使用及测试代码:

Expression<Func<int, bool>> condition1 = x => x > 8;
Expression<Func<int, bool>> condition2 = y => y < 3;            
var condition = condition1.Or(condition2);
var result = Enumerable
    .Range(1, 10)
    .Where(condition.Compile())
    .ToList();      //1,2,9,10

【讨论】:

  • 看起来 OP 不想要 OR 操作,但有条件地应用 Where。
  • @Cheng 这个!用 AND 动态组合条件是微不足道的,但是 OR... 我设法做一些类似但“手动”构建表达式的事情,例如 Expression.Equal(Expression.Property... , Expression.Constant...)。这更优雅!谢谢!
【解决方案3】:

我编写了一些代码来展示Predicate&lt;&gt;,同时试图坚持你的程序结构:

using System;
using System.Collections.Generic;
using System.Linq;

namespace SOTests
{
    public class MyModel
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    class Program
    {
        private static int ControlId;
        private static string ControlName;

        static void Main(string[] args)
        {
            var idPred = new Predicate<MyModel>(m => m.Id > ControlId);
            var namePred = new Predicate<MyModel>(m => m.Name == ControlName);

            var list = new List<MyModel>();

            if (true) // TODO: do id check?
            {
                list = list.Where(m => idPred.Invoke(m)).ToList();
            }

            if (true) // TODO: do name check?
            {
                list = list.Where(m => namePred.Invoke(m)).ToList();
            }

            //var fq = Session.Query<MyModel>();
            //fq = list;
        }
    }
}

我注释掉了 Session 位,不知道它代表哪种存储抽象(并且代码无法编译)。

代码应自行解释且未经测试。

它可以更优雅,但你应该更清楚地说明你的要求。

【讨论】:

    【解决方案4】:

    谢谢大家,我找到了解决方案:OrElse

    Expression<Func<MyModel, bool>> OrExpressionFunction(Expression<Func<MyModel, bool>> exp1, Expression<Func<MyModel, bool>> exp2)
        {
            ParameterExpression p = exp1.Parameters.Single();
            return Expression.Lambda<Func<MyModel, bool>>(
                Expression.OrElse(exp1.Body, exp2.Body), p);
        }
    

    然后:

    Expression<Func<MyModel, bool>> MyExp = null;
    if(sth){
      func = p => p.a <= b;
      MyExp= OrExpressionFunction(func, MyExp);
    }
    if (sth else){
      func = p => p.c >= d;
      MyExp= OrExpressionFunction(func, MyExp);
    }
    list.Add(MyExp);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-09
      • 2013-12-09
      • 2013-06-25
      • 2017-06-20
      相关资源
      最近更新 更多