2010-07-20 6 views
14

Comment combiner deux expressions lambda en une en utilisant un OU?Expressions lambda et comment les combiner?

Je l'ai essayé ce qui suit, mais leur fusion me demande de passer des paramètres dans les Expression.Invoke appels, mais je veux que la valeur passée dans le nouveau lambda à passer sur chaque enfant lambda ..

Expression<Func<int, bool>> func1 = (x) => x > 5; 
Expression<Func<int, bool>> func2 = (x) => x < 0; 
//Combines the lambdas but result in runtime error saying I need to pass in arguments 
//However I want the argument passed into each child lambda to be whatever is passed into the new main lambda 
Expression<Func<int, bool>> lambda = Expression.Lambda<Func<int, bool>>(Expression.Or(Expression.Invoke(func1), Expression.Invoke(func2))); 

//The 9 should be passed into the new lambda and into both child lambdas 
bool tst = lambda.Compile().Invoke(9); 

Des idées comment combiner deux expressions lambda en une et avoir les arguments de l'enfant lambdas être celui du parent?

+1

Quand vous dites «combiner», qu'est-ce que vous voulez vraiment que ce soit? Dites que l'argument passé est '7' -' func1' retournera vrai, et 'func2' retournera false. Que voulez-vous que la combinaison retourne? –

Répondre

18

Le meilleur moyen que j'ai trouvé pour apprendre des expressions, est de jeter un oeil au code source de PredicateBuilder.

Lorsque vous voulez combiner plusieurs de vos déclarations, vous pouvez:

Expression<Func<int, bool>> func1 = (x) => x > 5; 
Expression<Func<int, bool>> func2 = (x) => x > 10; 

var invocation = Expression.Invoke(func2, func1.Parameters.Cast<Expression>()); 
var expression = Expression.Lambda<Func<int, bool>>(Expression.OrElse(func1.Body, invocation), func1.Parameters); 

Le Expression.Invoke crée un InvocationExpression qui applique les paramètres à votre func2.

En fait, PredicateBuilder peut être tout ce dont vous avez besoin.

var predicate = PredicateBuilder.False<int>(); 
predicate = predicate.Or(x => x > 5); 
predicate = predicate.Or(x => x > 10); 

Je réviserait « x > 5 ou x > 10 », semble être une chose étrange à OU.

Espérons que ça aide.

+0

Excellent, c'est exactement ce que je cherchais. –

+1

'Expression.Lamda' manque un 'b', il devrait être .Expression.Lambda ' – Bern

+2

'Expression.Invoke' n'est pas supporté par Linq to Entities. Donc, bien que cela va compiler à IL. Il ne compilera pas à SQL. – Aron

1

Son intéressant ... Je ne connais pas beaucoup l'expression de lambda, mais j'ai trouvé this article. Sous PredicateBuilder code source est un exemple pour ou qui fonctionne pour moi:

public static Expression<Func<T, bool>> Or<T>(
         this Expression<Func<T, bool>> expr1, 
         Expression<Func<T, bool>> expr2) 
{ 
    var invExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>()); 
    return Expression.Lambda<Func<T, bool>> 
     (Expression.OrElse(expr1.Body, invExpr), expr1.Parameters); 
} 
0

** edit: oups lu sur la chose OU, mis à jour il ***

Salut,

Vous ne savez pas si vous voulez juste les appeler seperatley ou vous voulez les combiner d'un point de vue académique.

Vous pouvez les appeler comme ceci:

bool OR(int i1, Func<int, bool> f1, Func<int, bool> f2){ 
    return f1(i1) || f2(i1); 
} 

Cela fera l'affaire.

ou vous pouvez réécrire que

bool MyOR = (i1, f1, f2) => f1(i1) || f2(i1); 

Et quand vous êtes qurious, créez une expression de cela et regarder cela. (Faire à la main, ne t ont VS ici maintenant, donc s'il vous plaît être facile sur mes fautes de frappe)

Expression<Func<int, Func<int, bool>, Func<int, bool>, bool>> exprOR = 
(i1, f1, f2) => f1(i1) || f2(i1); 

Si vous voulez regarder l'anatomie de l'expression, vous pouvez regarder cet article je l'ai écrit: http://www.codeproject.com/KB/WPF/WpfExpressionTree.aspx

Il suffit de passer l'expression à l'apadater et de voir comment elle s'est construite.

Cordialement Gert-Jan

1

Pourquoi ne pas le faire:

Func<int, bool> func1 = (x) => x > 5; 
Func<int, bool> func2 = (x) => x > 10; 

List<Func<int, bool>> funcs = new List<Func<int, bool>> { func1, func2 }; 

var value = 7; 

Console.WriteLine(funcs.Any(x => x(value))); // OR 
Console.WriteLine(funcs.All(x => x(value))); // AND 

?

Enrichit les bibliothèques tierces.

+0

Problème est que je veux garder ces dans un arbre d'expression, donc ils sont analysés par cadre d'entité ... –

+1

Assez juste, ma suggestion n'est probablement pas viable alors –

Questions connexes