有条件地应用 Where(或在它们之间)LINQ
Apply Where conditionally (OR between them) LINQ
我的 asp.net 项目中有过滤器,并希望将表达式添加到此列表,条件为:
Expression<Func<MyModel, bool>> func;
var list = new List<Expression<Func<MyModel, bool>>>();
我想有条件地应用 Where(或它们之间)。例如:
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));
我该怎么做?
看起来你可以使用扩展方法轻松地做到这一点
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);
您可以构建一个扩展方法来使用 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
我编写了一些代码来展示 Predicate<>
,同时试图坚持您的程序结构:
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
位,不知道它代表哪种存储抽象(并且代码无法编译)。
代码应该会自行解释并且没有经过测试。
它可以更优雅,但你应该更清楚地说明你的要求是什么。
谢谢大家,我找到了解决方案: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);
我的 asp.net 项目中有过滤器,并希望将表达式添加到此列表,条件为:
Expression<Func<MyModel, bool>> func;
var list = new List<Expression<Func<MyModel, bool>>>();
我想有条件地应用 Where(或它们之间)。例如:
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));
我该怎么做?
看起来你可以使用扩展方法轻松地做到这一点
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);
您可以构建一个扩展方法来使用 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
我编写了一些代码来展示 Predicate<>
,同时试图坚持您的程序结构:
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
位,不知道它代表哪种存储抽象(并且代码无法编译)。
代码应该会自行解释并且没有经过测试。
它可以更优雅,但你应该更清楚地说明你的要求是什么。
谢谢大家,我找到了解决方案: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);