Expression.Or, el parámetro 'item' no está en el alcance
-
03-07-2019 - |
Pregunta
Estoy intentando escribir una función estática en O dos expresiones, pero recibo el siguiente error:
El parámetro 'elemento' no está dentro del alcance.
Descripción: Una excepción no controlada ocurrido durante la ejecución del solicitud web actual. Por favor revise el seguimiento de la pila para obtener más información acerca de El error y donde se originó. el código.
Detalles de la excepción: System.InvalidOperationException: La el parámetro 'item' no está dentro del alcance.
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);
}
editar : agregar más información
Las expresiones que están siendo o están viniendo del método a continuación, que se ejecutan bien. Si hay una mejor manera de hacerlo o los resultados soy todo oídos. Además, no sé cuántos se están haciendo 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);
}
editar : agregar aún más información
Alternativamente, ¿hay una mejor manera de hacer un o? Actualmente, la .Where (restricción) funciona bien donde la restricción es de tipo Expresión > ¿Cómo puedo hacer dónde? (Restricción1 o restricción2) (a la restricción n'th)
Gracias de antemano!
Solución
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 volver a escribir las partes izquierda y derecha para usar la nueva ParameterExpression. O pasar la ParameterExpression original a lo largo. No es porque los dos ParameterExpression tienen el mismo nombre que representan el mismo parámetro.
Otros consejos
Como ya se sugirió, aquí puede encontrar este código muy bueno (funcional)
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á vinculado (IMHO) a LINQ.
No estoy seguro 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án lo mismo si se usan en una expresión.
La mejor manera de lidiar con esto es crear un parámetro por adelantado para tu expresión, y luego pasarlo a todas las funciones de ayuda que necesitan el parámetro.
EDITAR: Además, si está intentando componer dinámicamente las cláusulas where en LINQ, puede dar PredicateBuilder a try.
Para aquellos que encontraron esta página en un motor de búsqueda y usarán PredicateBuilder de Ben & Joe Albahari , tenga cuidado, ya que no funciona con Entity Framework .
Prueba esta versión corregida en su lugar.
La solución de Fabrizio también se me ocurrió también, pero como estaba intentando combinar dos expresiones que se ejecutarían como una consulta de sql 2 sql, pensé que se ejecutaría en la memoria en lugar del servidor sql.
Me escribieron: Linq-To-Sql reconoce que la invocación es de una expresión lambda y, por lo tanto, sigue produciendo sql optimizado.