2010-12-11 19 views
17

Sto cercando un modo per negare un'espressione usata per filtrare le sequenze IQueryable.C# nega un'espressione

Così, ho qualcosa di simile:

Expression<Func<T, bool>> expression = (x => true); 

Ora desidero creare l'espressione che si tradurrebbe nel cedere (x => false) - così ho praticamente voglio negare l'expression.

Il metodo di lavoro che ho trovato me stesso funziona così:

var negatedExpression = 
    Expression.Lambda<Func<T, bool>> (Expression.Not(expression.Body), 
            expression.Parameters[0]))); 

Ma io sono quasi sicuro che c'è un modo migliore - mi può aiutare? (qualcosa come Not(expression), probabilmente).

risposta

17

un metodo di estensione facile:

public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> one) 
{ 
    var candidateExpr = one.Parameters[0]; 
    var body = Expression.Not(one.Body); 

    return Expression.Lambda<Func<T, bool>>(body, candidateExpr); 
} 

Usage:

Expression<Func<int, bool>> condition = x => x > 5; 
var source = Enumerable.Range(1, 10); 
var result1 = source.Where(condition.Compile()); //6,7,8,9,10 
var result2 = source.Where(condition.Not().Compile()); //1,2,3,4,5 
+0

Beh, so come avvolgere il mio modo di negare un'istruzione in un metodo 'Not', ma in realtà stavo cercando un modo semplice per eseguire effettivamente la negazione * (mi sembra che chiama 'Expression.Lambda. Blablabla' è un enorme overkill. * –

+2

Gli alberi di espressione sono immutabili, quindi devi creare un nuovo lambda. –

-2

Che dire di questo?

Expression<Func<bool>> expr =() => true; 
Expression<Func<bool>> negated =() => !expr.Compile()(); 
+0

Hai appena trasformato l'espressione di input in una chiamata di metodo opaca. Questo non aiuta affatto poiché lo scopo di usare un'espressione è che la query fornita può capirlo. – CodesInChaos

1

distacco per riferimento futuro.

risposta di Danny Chen può essere reso più generico:

public static Expression<TFunc> Not<TFunc>(this Expression<TFunc> baseExpr) 
{ 
    var param = baseExpr.Parameters; 
    var body = Expression.Not(baseExpr.Body); 
    var newExpr = Expression.Lambda<TFunc>(body, param); 
    return newExpr; 
} 

Questa versione può ricevere un'espressione con qualsiasi numero di parametri di input. Aggiunge solo un po 'di usabilità, tuttavia, poiché l'espressione verrebbe probabilmente passata a una funzione come IEnumerable.Where.