2009-01-04 7 views
8

Estoy tratando de escribir una función estática a uno o dos expresiones, pero recibo el siguiente error:Expression.Or, el 'elemento' parámetro no está en el ámbito

The parameter 'item' is not in scope.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: The parameter 'item' is not in scope.

el método:

public static Expression<Func<T, bool>> OrExpressions(Expression<Func<T, bool>> left, Expression<Func<T, bool>> right) 
{ 
    // Define the parameter to use 
    var param = Expression.Parameter(typeof(T), "item"); 

    var filterExpression = Expression.Lambda<Func<T, bool>> 
     (Expression.Or(
      left.Body, 
      right.Body 
     ), param); 
    // Build the expression and return it 
    return (filterExpression); 
} 

edición: la adición de más información

las expresiones están usando OR están llegando desde el siguiente método, que ejecuta muy bien. si hay una mejor manera o los resultados, soy todo oídos. Además, no sé cuántos se están haciendo o por adelantado.

public static Expression<Func<T, bool>> FilterExpression(string filterBy, object Value, FilterBinaryExpression binaryExpression) 
{ 
    // Define the parameter to use 
    var param = Expression.Parameter(typeof(T), "item"); 

    // Filter expression on the value 
    switch (binaryExpression) 
    { 
     case FilterBinaryExpression.Equal: 
      { 
       // Build an expression for "Is the parameter equal to the value" by employing reflection 
       var filterExpression = Expression.Lambda<Func<T, bool>> 
        (Expression.Equal(
         Expression.Convert(Expression.Property(param, filterBy), typeof(TVal)), 
         Expression.Constant(Value) 
        ), 
        param); 
       // Build the expression and return it 
       return (filterExpression); 
      } 

edición: añadiendo aún más información

Por otra parte, hay una mejor manera de hacer una o? Actualmente, .Where (restricción) funciona bien donde la restricción es de tipo Expresión>. ¿Cómo puedo hacer dónde (constraint1 o constraint2) (a la restricción n'th)

¡Gracias de antemano!

Respuesta

9

El problema es que la expresión que está creando en el método OrExpressions reutiliza el cuerpo de las dos expresiones. Esos cuerpos contendrán referencias a su propia ParameterExpression que se ha definido en FilterExpression.

Una solución sería reescribir las partes izquierda y derecha para usar la nueva ParameterExpression. O para pasar el parámetro ParameterExpression original. No es porque los dos ParameterExpression tengan el mismo nombre que ellos representan el mismo parámetro.

+0

¡Gracias! Intentando pasar el mismo parámetro ahora – ccook

+0

Eres mi amigo, eres increíble :) – ccook

2

No estoy seguro acerca de los términos adecuados aquí, pero básicamente los parámetros de expresión no son equivalentes, incluso si tienen el mismo nombre.

Eso significa que

var param1 = Expression.Parameter(typeof(T), "item"); 
var param2 = Expression.Parameter(typeof(T), "item"); 

param1 != param2 

param1 y param2 no será el mismo que si se utiliza en una expresión.

La mejor manera de lidiar con esto es crear un parámetro por adelantado para su expresión, y luego pasarlo a todas las funciones auxiliares que necesitan el parámetro.

EDITAR: Además, si intenta componer dinámicamente cláusulas where en LINQ, podría intentar PredicateBuilder.

+0

Gracias :) Reformé el método para pasar el mismo parámetro a los métodos del ayudante y todo está bien otra vez. Estoy buscando en el PredicateBuilder para limpiar las cosas – ccook

+0

Tenga cuidado, ya que el PredicateBuilder de Ben & Joe Albahari no funciona para Entity Framework. Ver mi respuesta para una versión fija. –

4

Como ya se ha sugerido, here puede encontrar este código muy agradable (de trabajo)

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

que puede adaptarse a sus necesidades y que no está atado (en mi humilde opinión) a LINQ.

+0

Agradable y limpio, ty – ccook

+0

Tenga cuidado, ya que este código no funciona para Entity Framework. Ver mi respuesta para una versión fija. –

1

También se me ocurrió la solución de Fabrizio, pero como estaba intentando combinar dos expresiones que se ejecutarían como una consulta de linq 2 sql, pensé que se ejecutaría en memoria en lugar de hacerlo en el servidor sql.

Me escribieron - Linq-To-Sql reconoce que la invocación es de una expresión lambda y, por lo tanto, aún produce sql optimizado.

2

Para aquellos, que encontró esta página mediante un motor de búsqueda y que se va a utilizar el PredicateBuilder de Ben & Joe Albahari, ten cuidado, ya que no funciona con el marco de la entidad.

Pruebe this fixed version en su lugar.

Cuestiones relacionadas