Expression.Or, o parâmetro 'item' não está no escopo
-
03-07-2019 - |
Pergunta
Estou tentando escrever uma função estática para duas expressões, mas recebo o seguinte erro:
O parâmetro 'item' não está no escopo.
Descrição:Uma exceção não tratada ocorreram durante a execução do solicitação web atual.Por favor, reveja o Rastreamento de pilha para obter mais informações sobre o erro e onde ele se originou em o código.
Detalhes da exceção:System.InvalidOperationException:O O parâmetro 'item' não está no escopo.
o 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:adicionando mais informações
As expressões or'd vêm do método abaixo, que funciona perfeitamente.se existe uma maneira melhor ou os resultados sou todo ouvidos.Além disso, não sei quantos estão sendo agendados com antecedência.
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:adicionando ainda mais informações
Alternativamente, existe uma maneira melhor de fazer um ou?Atualmente o .Where(constraint) funciona bem onde a restrição é do tipo Expression>.Como posso fazer where(restrição1 ou restrição2) (para a restrição n'ésima)
Desde já, obrigado!
Solução
A questão é que a expressão que você está criando no método orexpressions reutiliza o corpo das duas expressões. Esses corpos conterão referências à sua própria parameterexpressão que foi definida na expressão do filtro.
Uma correção seria reescrever as partes esquerda e direita para usar a nova Parameterexpression. Ou passar a temerexpressão original. Não é porque as duas parameterexpressão têm o mesmo nome que representam o mesmo parâmetro.
Outras dicas
Como já sugerido, aqui Você pode encontrar este código muito bom (funcionando)
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 você pode se adaptar às suas necessidades e que não está vinculado (IMHO) ao LINQ.
Não tenho certeza sobre os termos adequados aqui, mas basicamente os parâmetros de expressão não são equivalentes, mesmo que tenham o mesmo nome.
Isso significa que
var param1 = Expression.Parameter(typeof(T), "item");
var param2 = Expression.Parameter(typeof(T), "item");
param1 != param2
param1 e param2 não serão a mesma coisa se usados em uma expressão.
A melhor maneira de lidar com isso é criar um parâmetro antecipadamente para sua expressão e, em seguida, passá-lo para todas as funções auxiliares que precisam do parâmetro.
EDITAR:Além disso, se você estiver tentando compor cláusulas where dinamicamente no LINQ, poderá fornecer PredicadoBuilder uma tentativa.
Para aqueles que encontraram esta página por um mecanismo de pesquisa e vão usar O PredicateBuilder de Ben e Joe Albahari, cuidado, já que não funciona com a estrutura da entidade.
Tentar esta versão fixa em vez de.
A solução de Fabrizio também me ocorreu também, mas como eu estava tentando combinar duas expressões que seriam executadas como uma consulta SQL LINQ 2, pensei que ela seria executada na memória e não no servidor SQL.
Fui escrito-Linq-to-SQL reconhece que a invocação é de expressão de Lambda e, portanto, ainda produz SQL otimizado.