2010-07-20 10 views
14

¿Cómo puedo combinar dos expresiones lambda en una usando un OR?Expresiones Lambda y cómo combinarlas?

He intentado el siguiente, pero su fusión me obliga a pasar parámetros en los Expression.Invoke llamadas, sin embargo quiero que el valor pasado en el nuevo lambda que se hace llegar a cada niño-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); 

¿Alguna idea de cómo combinar dos expresiones lambda en una sola y que los argumentos de los lambdas secundarios sean los del padre?

+1

Cuando dice "combinar", ¿qué es lo que realmente quiere que suceda? Diga que el argumento pasado es '7' -' func1' devolverá verdadero, y 'func2' devolverá falso. ¿Qué quieres que vuelva la combinación? –

Respuesta

18

La mejor manera que he encontrado para aprender expresiones, es echar un vistazo al código fuente de PredicateBuilder.

Cuando se desea combinar múltiples sus estados de cuenta, puede:

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); 

El Expression.Invoke crea un InvocationExpression que aplica los parámetros a su func2.

De hecho, PredicateBuilder puede ser todo lo que necesita.

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

Me gustaría revisar "x > 5 o x > 10", parece como una cosa extraña a O.

Espero que ayude.

+0

Excelente, esto es justo lo que estaba buscando. –

+1

'Expression.Lamda' falta una 'b', por lo que debe ser .Expression.Lambda ' – Bern

+2

' Expression.Invoke 'no es compatible con Linq para Entidades por cierto. Entonces, aunque esto compilará a IL. No compilará a SQL. – Aron

1

Sonido interesante ... No sé mucho sobre la expresión lambda, pero encontré this article. Bajo Código Fuente PredicateBuilder es un ejemplo para o que funciona para mí:

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

** edición: oops leer sobre la cosa o, puesto al día ***

Hola,

No estoy seguro si solo quiere llamarlos por separado o si desea combinarlos desde un punto de vista académico.

Usted sólo puede llamarlos así:

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

que va a hacer el truco.

o puede volver a escribir que a medida que

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

Y cuando estás qurious, crear una expresión de eso y mira eso. (Hacer esto a mano, Don; t tiene VS aquí ahora, así que por favor sea fácil en mis errores tipográficos)

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

Si desea buscar en la anatomía de la expresión, se puede ver en este artículo que escribí: http://www.codeproject.com/KB/WPF/WpfExpressionTree.aspx

Simplemente pase la expresión al apadater y vea cómo se construyó.

Saludos Gert-Jan

1

¿Por qué no hacer:

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 

?

Guarda el lío con bibliotecas de terceros.

+0

El problema es que quiero mantener estos en un árbol de expresiones, por lo que son analizados por entidad marco ... –

+1

Bastante, mi sugerencia probablemente no es tan viable, entonces –