Expression.Or, Il parametro 'item' non rientra nell'ambito
-
03-07-2019 - |
Domanda
Sto provando a scrivere una funzione statica su O due espressioni, ma ricevo il seguente errore:
Il parametro 'item' non rientra nell'ambito.
Descrizione: un'eccezione non gestita si è verificato durante l'esecuzione del richiesta web corrente. Si prega di rivedere il stack stack per ulteriori informazioni su l'errore e la sua origine il codice.
Dettagli eccezione: System.InvalidOperationException: The il parametro 'item' non rientra nell'ambito.
il metodo:
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);
}
modifica : aggiunta di ulteriori informazioni
Le espressioni essendo o verrebbero dal metodo seguente, che viene eseguito correttamente. se c'è un modo migliore per o i risultati sono tutto orecchie. Inoltre, non so quanti ne siano stati o lo farebbero in anticipo.
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);
}
modifica : aggiunta di ulteriori informazioni
In alternativa, c'è un modo migliore per fare un o? Attualmente il .Where (vincolo) funziona perfettamente quando il vincolo è di tipo Expression > ;. Come posso fare dove (vincolo1 o vincolo2) (al vincolo n)
Grazie in anticipo!
Soluzione
Il problema è che l'espressione che stai creando nel metodo OrExpressions riutilizza il corpo delle due espressioni. Tali corpi conterranno riferimenti alla propria ParameterExpression che è stata definita in FilterExpression.
Una correzione sarebbe quella di riscrivere le parti sinistra e destra per usare il nuovo ParameterExpression. Oppure per passare l'espressione ParameterExpression originale. Non è perché i due ParameterExpression hanno lo stesso nome che rappresentano lo stesso parametro.
Altri suggerimenti
Come già suggerito, qui puoi trovare questo bellissimo codice (funzionante)
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);
}
che puoi adattare alle tue esigenze e che non è legato (IMHO) a LINQ.
Non sono sicuro dei termini corretti qui, ma sostanzialmente i parametri di espressione non sono equivalenti anche se hanno lo stesso nome.
Ciò significa che
var param1 = Expression.Parameter(typeof(T), "item");
var param2 = Expression.Parameter(typeof(T), "item");
param1 != param2
param1 e param2 non saranno la stessa cosa se usati in un'espressione.
Il modo migliore per gestirlo è creare un parametro in anticipo per la tua espressione, quindi passarlo a tutte le funzioni di supporto che richiedono il parametro.
EDIT: Inoltre, se stai cercando di comporre dinamicamente le clausole where in LINQ, potresti dare PredicateBuilder una prova.
Per coloro che hanno trovato questa pagina da un motore di ricerca e useranno PredicateBuilder di Ben & amp; Joe Albahari , attenzione, poiché non funziona con Entity Framework .
Prova questa versione fissa invece.
Anche la soluzione di Fabrizio mi è venuta in mente, ma dal momento che stavo tentando di combinare due espressioni che sarebbero state eseguite come una query linq 2 sql, ho pensato che sarebbe stato eseguito in memoria piuttosto che nel server sql.
Sono stato scritto - Linq-To-Sql riconosce che l'invocazione è un'espressione lambda e quindi produce ancora sql ottimizzato.