我有两个表达式的类型表达式<Func<T, bool>>和我想采取或,与或不是这些,并获得一个相同类型的新表达式
Expression<Func<T, bool>> expr1;
Expression<Func<T, bool>> expr2;
...
//how to do this (the code below will obviously not work)
Expression<Func<T, bool>> andExpression = expr AND expr2
我有两个表达式的类型表达式<Func<T, bool>>和我想采取或,与或不是这些,并获得一个相同类型的新表达式
Expression<Func<T, bool>> expr1;
Expression<Func<T, bool>> expr2;
...
//how to do this (the code below will obviously not work)
Expression<Func<T, bool>> andExpression = expr AND expr2
当前回答
我觉得这样挺好的,不是吗?
Func<T, bool> expr1 = (x => x.Att1 == "a");
Func<T, bool> expr2 = (x => x.Att2 == "b");
Func<T, bool> expr1ANDexpr2 = (x => expr1(x) && expr2(x));
Func<T, bool> expr1ORexpr2 = (x => expr1(x) || expr2(x));
Func<T, bool> NOTexpr1 = (x => !expr1(x));
其他回答
我建议对PredicateBuilder和ExpressionVisitor解决方案再做一个改进。我把它叫做UnifyParametersByName,你可以在我的MIT库LinqExprHelper中找到它。它允许组合任意lambda表达式。通常问题是关于谓词表达式的,但是这个想法也可以扩展到投影表达式。
下面的代码使用了ExprAdres方法,它使用内联lambda创建了一个复杂的参数化表达式。这个复杂的表达式只编码一次,然后重用,这要感谢LinqExprHelper迷你库。
public IQueryable<UbezpExt> UbezpFull
{
get
{
System.Linq.Expressions.Expression<
Func<UBEZPIECZONY, UBEZP_ADRES, UBEZP_ADRES, UbezpExt>> expr =
(u, parAdrM, parAdrZ) => new UbezpExt
{
Ub = u,
AdrM = parAdrM,
AdrZ = parAdrZ,
};
// From here an expression builder ExprAdres is called.
var expr2 = expr
.ReplacePar("parAdrM", ExprAdres("M").Body)
.ReplacePar("parAdrZ", ExprAdres("Z").Body);
return UBEZPIECZONY.Select((Expression<Func<UBEZPIECZONY, UbezpExt>>)expr2);
}
}
这是子表达式的构建代码:
public static Expression<Func<UBEZPIECZONY, UBEZP_ADRES>> ExprAdres(string sTyp)
{
return u => u.UBEZP_ADRES.Where(a => a.TYP_ADRESU == sTyp)
.OrderByDescending(a => a.DATAOD).FirstOrDefault();
}
我试图实现的是执行参数化查询,而不需要复制粘贴,并能够使用内联lambdas,这非常漂亮。如果没有这些帮助表达式,我将被迫一次性创建整个查询。
我觉得这样挺好的,不是吗?
Func<T, bool> expr1 = (x => x.Att1 == "a");
Func<T, bool> expr2 = (x => x.Att2 == "b");
Func<T, bool> expr1ANDexpr2 = (x => expr1(x) && expr2(x));
Func<T, bool> expr1ORexpr2 = (x => expr1(x) || expr2(x));
Func<T, bool> NOTexpr1 = (x => !expr1(x));
我需要实现相同的结果,但是使用一些更通用的东西(因为不知道类型)。多亏了marc的回答,我终于明白了我想要达到的目标:
public static LambdaExpression CombineOr(Type sourceType, LambdaExpression exp, LambdaExpression newExp)
{
var parameter = Expression.Parameter(sourceType);
var leftVisitor = new ReplaceExpressionVisitor(exp.Parameters[0], parameter);
var left = leftVisitor.Visit(exp.Body);
var rightVisitor = new ReplaceExpressionVisitor(newExp.Parameters[0], parameter);
var right = rightVisitor.Visit(newExp.Body);
var delegateType = typeof(Func<,>).MakeGenericType(sourceType, typeof(bool));
return Expression.Lambda(delegateType, Expression.Or(left, right), parameter);
}
这里没有什么新东西,只是把这个答案和这个答案结合起来,稍微重构了一下,这样即使是我也能理解发生了什么:
public static class ExpressionExtensions
{
public static Expression<Func<T, bool>> AndAlso<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
{
ParameterExpression parameter1 = expr1.Parameters[0];
var visitor = new ReplaceParameterVisitor(expr2.Parameters[0], parameter1);
var body2WithParam1 = visitor.Visit(expr2.Body);
return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(expr1.Body, body2WithParam1), parameter1);
}
private class ReplaceParameterVisitor : ExpressionVisitor
{
private ParameterExpression _oldParameter;
private ParameterExpression _newParameter;
public ReplaceParameterVisitor(ParameterExpression oldParameter, ParameterExpression newParameter)
{
_oldParameter = oldParameter;
_newParameter = newParameter;
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (ReferenceEquals(node, _oldParameter))
return _newParameter;
return base.VisitParameter(node);
}
}
}
using System;
using System.Linq.Expressions;
namespace Extensions
{
public class Example
{
//How to use it
public static void Main()
{
Expression<Func<string, bool>> expression1 = exp => true;
Expression<Func<string, bool>> expression2 = exp => false;
Expression<Func<string, bool>> expression3 = ExpressionExtensions.AndAlso(expression1, expression2);
Expression<Func<string, bool>> expression4 = ExpressionExtensions.OrElse(expression1, expression2);
Expression<Func<string, bool>> expression = ExpressionExtensions.AndAlso(expression3, expression4);
}
}
public static class ExpressionExtensions
{
public static Expression<Func<T, bool>> AndAlso<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
{
ParameterExpression parameter1 = expr1.Parameters[0];
var visitor = new ReplaceParameterVisitor(expr2.Parameters[0], parameter1);
var body2WithParam1 = visitor.Visit(expr2.Body);
return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(expr1.Body, body2WithParam1), parameter1);
}
public static Expression<Func<T, bool>> OrElse<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
{
ParameterExpression parameter1 = expr1.Parameters[0];
var visitor = new ReplaceParameterVisitor(expr2.Parameters[0], parameter1);
var body2WithParam1 = visitor.Visit(expr2.Body);
return Expression.Lambda<Func<T, bool>>(Expression.OrElse(expr1.Body, body2WithParam1), parameter1);
}
private class ReplaceParameterVisitor : ExpressionVisitor
{
private readonly ParameterExpression _oldParameter;
private readonly ParameterExpression _newParameter;
public ReplaceParameterVisitor(ParameterExpression oldParameter, ParameterExpression newParameter)
{
_oldParameter = oldParameter;
_newParameter = newParameter;
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (ReferenceEquals(node, _oldParameter))
return _newParameter;
return base.VisitParameter(node);
}
}
}
}