2010-12-11 36 views
17

Estoy buscando una manera de negar una expresión utilizada para filtrar las secuencias IQueryable.C# negar una expresión

Por lo tanto, tengo algo como:

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

Ahora quiero crear la expresión de lo que resultaría en ceder (x => false) - así que básicamente quiero negar la expression.

El método de trabajo me he encontrado funciona así:

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

pero estoy casi seguro de que hay una manera mejor - usted me podría ayudar? (algo así como Not(expression), probablemente).

Respuesta

17

Un sencillo método de extensión:

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); 
} 

Uso:

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

Bueno, sé cómo abrirme camino para negar una afirmación en un método 'No', pero en realidad estaba buscando una manera fácil de realizar realmente la negación * (me parece que llamar a 'Expression.Lambda. Blablabla' es una gran exageración). * –

+2

Los árboles de expresión son inmutables, por lo que debes crear una nueva lambda. –

-2

¿Qué tal esto?

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

Acaba de convertir la expresión de entrada en una llamada de método opaco. Esto no ayuda en absoluto ya que el propósito de usar una expresión es que la consulta proporcionada puede entenderlo. – CodesInChaos

1

de entradas para obtener futuras referencias.

respuesta de Danny Chen se pueden hacer más genérico:

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; 
} 

Esta versión puede recibir una expresión con cualquier número de parámetros de entrada. Sin embargo, solo agrega un poco de usabilidad, ya que la Expresión probablemente pase a una función como IEnumerable.Where de todos modos.