Eh bien, vous pouvez utiliser Expression.AndAlso
/ OrElse
etc pour combiner des expressions logiques, mais le problème est que les paramètres; travaillez-vous avec le même ParameterExpression
dans expr1 et expr2? Si oui, il est plus facile:
var body = Expression.AndAlso(expr1.Body, expr2.Body);
var lambda = Expression.Lambda<Func<T,bool>>(body, expr1.Parameters[0]);
Cela fonctionne aussi bien pour annuler une opération unique:
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]);
}
Sinon, en fonction de l'LINQ fournisseur, vous pourriez être en mesure de les combiner avec d' 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;
}
Quelque part, j'ai eu un peu de code qui ré-écrit une expression de l'arbre-remplacement de nœuds pour éliminer le besoin d' Invoke
, mais il est assez long (et je ne me souviens pas où je l'ai laissé...)
Version généralisée qui choisit la route la plus simple:
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);
}