Cet article montre comment combiner deux expressions C # de type Expression<Func<bool>>
en utilisant logique et, ou, et non opérateurs. L'utilisation directe d'opérateurs comme expr1 AND expr2
est incorrect en raison de décalages de paramètres. Plusieurs approches sont présentées, chacune abordant différents scénarios.
Méthode 1: combinaison simple (paramètres identiques)
Si les deux expressions utilisent le même paramètre, une approche simple consiste à utiliser Expression.AndAlso
ou Expression.OrElse
directement sur les corps d'expression:
<code class="language-csharp">var body = Expression.AndAlso(expr1.Body, expr2.Body); var lambda = Expression.Lambda<Func<bool>>(body, expr1.Parameters[0]);</code>
La négation est tout aussi simple:
<code class="language-csharp">static Expression<Func<bool>> Not<T>(this Expression<Func<bool>> expr) { return Expression.Lambda<Func<bool>>(Expression.Not(expr.Body), expr.Parameters[0]); }</code>
Méthode 2: combinant des expressions avec différents paramètres en utilisant invoquer
Lorsque les expressions ont des paramètres différents, la méthode Invoke
peut être utilisée pour créer une nouvelle expression de lambda avec un paramètre commun:
<code class="language-csharp">static Expression<Func<bool>> AndAlso<T>(this Expression<Func<bool>> left, Expression<Func<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<bool>>(body, param); return lambda; }</code>
OrElse
serait similaire, en remplaçant AndAlso
par OrElse
.
Méthode 3: combinaison optimisée (gère les paramètres identiques et différents)
Cette méthode choisit intelligemment l'approche plus simple si les paramètres sont les mêmes, autrement utilise Invoke
:
<code class="language-csharp">static Expression<Func<bool>> AndAlso<T>(this Expression<Func<bool>> expr1, Expression<Func<bool>> expr2) { ParameterExpression param = expr1.Parameters[0]; if (ReferenceEquals(param, expr2.Parameters[0])) { return Expression.Lambda<Func<bool>>(Expression.AndAlso(expr1.Body, expr2.Body), param); } return Expression.Lambda<Func<bool>>(Expression.AndAlso(expr1.Body, Expression.Invoke(expr2, param)), param); }</code>
Méthode 4: approche EF-SAFE Utilisation de l'expressionVisitor (.NET 4.0 et ultérieurement)
Pour la compatibilité du cadre d'entité, un ExpressionVisitor
fournit une solution robuste:
<code class="language-csharp">public static Expression<Func<bool>> AndAlso<T>(this Expression<Func<bool>> expr1, Expression<Func<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<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); } }</code>
Cette méthode remplace les références de paramètres dans les expressions pour assurer la compatibilité avec divers fournisseurs LINQ. Le choix de la méthode dépend des besoins et du contexte spécifiques de votre application, en particulier le fournisseur LINQ utilisé et si la cohérence des paramètres est garantie. L'approche ExpressionVisitor
offre la solution la plus robuste pour les scénarios complexes et l'intégration du cadre d'entité.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!