将两个前pressions(前pression&LT;&Func键LT; T,BOOL&GT;&GT;) [英] Combining two expressions (Expression<Func<T, bool>>)
问题描述
我型防爆pression&LT的两位前pressions; Func键&LT; T,BOOL&GT;&GT;
我要采取OR,AND或NOT的这些和得到相同的类型的新的前pression
防爆pression&LT;&Func键LT; T,BOOL&GT;&GT;表达式1;
防爆pression&LT;&Func键LT; T,BOOL&GT;&GT;表达式2;...//怎么办(以下code显然不会工作)这
防爆pression&LT;&Func键LT; T,BOOL&GT;&GT; ANDEX pression = EXPR和表达式2
好了,你可以使用防爆pression.AndAlso
/ OrElse运算
等逻辑EX pressions结合起来,但问题是参数;你在表达式1和表达式2相同的 ParameterEx pression
工作吗?如果是这样,这是更容易:
VAR体=前pression.AndAlso(expr1.Body,expr2.Body);
VAR波长=前pression.Lambda&LT;&Func键LT; T,BOOL&GT;&GT;(身体,expr1.Parameters [0]);
这也是行之有效的否定单一操作:
静态防爆pression&LT;&Func键LT; T,BOOL&GT;&GT;不&LT; T&GT;(
这种防爆pression&LT;&Func键LT; T,BOOL&GT;&GT;表达式)
{
返回前pression.Lambda&LT;&Func键LT; T,BOOL&GT;&GT;(
实施例pression.Not(expr.Body),expr.Parameters [0]);
}
另外,根据不同的LINQ提供程序,你也许可以将它们与调用
组合:
// OrElse运算很相似...
静态防爆pression&LT;&Func键LT; T,BOOL&GT;&GT; AndAlso运算&LT; T&GT;(
这种防爆pression&LT;&Func键LT; T,BOOL&GT;&GT;剩下,
防爆pression&LT;&Func键LT; T,BOOL&GT;&GT;对)
{
VAR参数=前pression.Parameter(typeof运算(T),X);
VAR体=前pression.AndAlso(
防爆pression.Invoke(左,参数),
防爆pression.Invoke(右帕拉姆)
);
VAR波长=前pression.Lambda&LT;&Func键LT; T,BOOL&GT;&GT;(机身,参数);
返回的lambda;
}
冥冥之中,我已经得到了一些code,它重新写一个前pression树替换节点删除调用
的需要,但它是相当长(我不记得在那里我把它...)
广义版本,采简单的路线:
静态防爆pression&LT;&Func键LT; T,BOOL&GT;&GT; AndAlso运算&LT; T&GT;(
这种防爆pression&LT;&Func键LT; T,BOOL&GT;&GT;表达式1,
防爆pression&LT;&Func键LT; T,BOOL&GT;&GT;表达式2)
{
//需要检测它们是否使用相同的
//参数实例;如果不是,他们需要固定
ParameterEx pression参数= expr1.Parameters [0];
如果(的ReferenceEquals(参数,expr2.Parameters [0]))
{
//简易版
返回前pression.Lambda&LT;&Func键LT; T,BOOL&GT;&GT;(
防爆pression.AndAlso(expr1.Body,expr2.Body),参数);
}
//否则,保持表达式1原样并调用表达式2
返回前pression.Lambda&LT;&Func键LT; T,BOOL&GT;&GT;(
防爆pression.AndAlso(
expr1.Body,
防爆pression.Invoke(表达式2,参数)),参数);
}
从.NET 4.0开始。有防爆pressionVistor类,它允许你建立前pressions是EF安全的。
公共静态防爆pression&LT;&Func键LT; T,BOOL&GT;&GT; AndAlso运算&LT; T&GT;(
这种防爆pression&LT;&Func键LT; T,BOOL&GT;&GT;表达式1,
防爆pression&LT;&Func键LT; T,BOOL&GT;&GT;表达式2)
{
变量参数=前pression.Parameter(typeof运算(T)); 变种leftVisitor =新ReplaceEx pressionVisitor(expr1.Parameters [0],参数);
VAR左= leftVisitor.Visit(expr1.Body); 变种rightVisitor =新ReplaceEx pressionVisitor(expr2.Parameters [0],参数);
VAR右= rightVisitor.Visit(expr2.Body); 返回前pression.Lambda&LT;&Func键LT; T,BOOL&GT;&GT;(
防爆pression.AndAlso(左,右),参数);
} 私有类ReplaceEx pressionVisitor
:防爆pressionVisitor
{
私人只读防爆pression _oldValue;
私人只读防爆pression _newValue; 公共ReplaceEx pressionVisitor(前pression属性oldValue,防爆pression newValue)以
{
_oldValue =属性oldValue;
_newValue =为newValue;
} 公共覆盖防爆pression访问(防爆pression节点)
{
如果(节点== _oldValue)
返回_newValue;
返回base.Visit(节点);
}
}
I have two expressions of type Expression<Func<T, bool>>
and I want to take to OR, AND or NOT of these and get a new expression of the same type
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
Well, you can use Expression.AndAlso
/ OrElse
etc to combine logical expressions, but the problem is the parameters; are you working with the same ParameterExpression
in expr1 and expr2? If so, it is easier:
var body = Expression.AndAlso(expr1.Body, expr2.Body);
var lambda = Expression.Lambda<Func<T,bool>>(body, expr1.Parameters[0]);
This also works well to negate a single operation:
static Expression<Func<T, bool>> Not<T>(
this Expression<Func<T, bool>> expr)
{
return Expression.Lambda<Func<T, bool>>(
Expression.Not(expr.Body), expr.Parameters[0]);
}
Otherwise, depending on the LINQ provider, you might be able to combine them with Invoke
:
// OrElse is very similar...
static Expression<Func<T, bool>> AndAlso<T>(
this Expression<Func<T, bool>> left,
Expression<Func<T, bool>> right)
{
var param = Expression.Parameter(typeof(T), "x");
var body = Expression.AndAlso(
Expression.Invoke(left, param),
Expression.Invoke(right, param)
);
var lambda = Expression.Lambda<Func<T, bool>>(body, param);
return lambda;
}
Somewhere, I have got some code that re-writes an expression-tree replacing nodes to remove the need for Invoke
, but it is quite lengthy (and I can't remember where I left it...)
Generalized version that picks the simplest route:
static Expression<Func<T, bool>> AndAlso<T>(
this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
// need to detect whether they use the same
// parameter instance; if not, they need fixing
ParameterExpression param = expr1.Parameters[0];
if (ReferenceEquals(param, expr2.Parameters[0]))
{
// simple version
return Expression.Lambda<Func<T, bool>>(
Expression.AndAlso(expr1.Body, expr2.Body), param);
}
// otherwise, keep expr1 "as is" and invoke expr2
return Expression.Lambda<Func<T, bool>>(
Expression.AndAlso(
expr1.Body,
Expression.Invoke(expr2, param)), param);
}
Starting from .net 4.0. There is the ExpressionVistor class which allows you to build expressions that are EF safe.
public static Expression<Func<T, bool>> AndAlso<T>(
this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var parameter = Expression.Parameter(typeof (T));
var leftVisitor = new ReplaceExpressionVisitor(expr1.Parameters[0], parameter);
var left = leftVisitor.Visit(expr1.Body);
var rightVisitor = new ReplaceExpressionVisitor(expr2.Parameters[0], parameter);
var right = rightVisitor.Visit(expr2.Body);
return Expression.Lambda<Func<T, bool>>(
Expression.AndAlso(left, right), parameter);
}
private class ReplaceExpressionVisitor
: ExpressionVisitor
{
private readonly Expression _oldValue;
private readonly Expression _newValue;
public ReplaceExpressionVisitor(Expression oldValue, Expression newValue)
{
_oldValue = oldValue;
_newValue = newValue;
}
public override Expression Visit(Expression node)
{
if (node == _oldValue)
return _newValue;
return base.Visit(node);
}
}
这篇关于将两个前pressions(前pression&LT;&Func键LT; T,BOOL&GT;&GT;)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!