2009-04-15 27 views
5

Me gustaría saber si es posible usar una expresión como variable/parámetro en C#. Me gustaría hacer algo como esto:C#: ¿Hay alguna forma de usar expresiones como variable/parámetro?

int x = 0; 
public void g() 
{ 
    bool greaterThan = f("x>2"); 
    bool lessThan = f("x<2"); 
} 
public bool f(Expression expression) 
{ 
    if(expression) 
     return true; 
    else 
     return false; 
} 

Esto es lo que no quiero hacer:

int x = 0; 
public void g() 
{ 
    bool greaterThan = f(x, '<', 2); 
} 

public bool f(int x, char c, int y) 
{ 
    if(c == '<') 
     return x < y; 
    if(c == '>') 
     return x > y; 
} 

Realmente lo que quiero llegar es una manera de evitar el uso de un interruptor o serie de sentencias if para cada uno de: <> < => = ==! =. ¿Hay una manera de hacerlo?

Editar: Supongamos que la expresión es una cadena, como "x < 2". ¿Hay alguna manera de pasar de la cadena a un predicado sin usar una serie de sentencias if sobre la condición?

Respuesta

11

Es muy posible, simplemente no en la sintaxis exacta que tiene.

int x = 0; 
public void g() 
{ 
    bool greaterThan = f(i => i > 2, x); 
    bool lessThan = f(i => i < 2, x); 
} 
public bool f(Func<int,bool> expression, int value) 
{ 
    return expression(value); 
} 

En realidad, esto debería estar más cerca de lo que desea.

int x = 0; 
public void g() 
{ 
    bool greaterThan = f(() => x > 2); 
    bool lessThan = f(() => x < 2); 
} 
public bool f(Func<bool> expression) 
{ 
    return expression(); 
} 

Responder a Editar

Si usted quiere ser capaz de decir f("x < 2"), que va a ser casi imposible. Ignorando el análisis (lo que podría volverse desagradable), debes capturar el valor de x, pero es solo un carácter a f, lo que hace que sea prácticamente imposible.

+0

Cool. Edité mi pregunta un poco de la siguiente manera: supongamos que la expresión es una cadena, como "x <2". ¿Hay alguna manera de pasar de la cadena a un predicado sin usar una serie de sentencias if sobre el personaje? –

+1

Si es realmente una cadena, no va a haber una respuesta fácil y rápida. Pero si quiere decir que quiere escribir f (x> 2) ;, simplemente haga que f tome un parámetro booleano. – Samuel

+0

Drats, ok. Gracias por la respuesta. –

9

Si realmente quiere pasar alrededor de código para esto, usted quiere un predicado:

int x = 0; 
public void g() 
{ 
    bool greaterThan = f(i => i>2, x); 
    bool lessThan = f(i => i<2, x); 
} 
public bool f(Predicate<int> expression, int value) 
{ 
    return expression(value); 
} 

De lo contrario, si sólo sustituir bool para Expression en su primer ejemplo su código se compilará bien:

int x = 0; 
public void g() 
{ 
    bool greaterThan = f(x>2); 
    bool lessThan = f(x<2); 
} 
public bool f(bool expression) 
{ 
    if(expression) 
     return true; 
    else 
     return false; 
} 
+0

Wow, ese downvote está completamente fuera de lugar. Esta respuesta es correcta y más en línea con lo que el interlocutor quería en términos de sintaxis. – Samuel

+0

Tenía un marcador de posición que era solo la primera frase, me tomó demasiado tiempo para completarlo. –

+0

En realidad, no puedes simplemente llamar a expression(). Tienes que pasar un int. – Samuel

7

A menos que me falta algo ... ¿Por qué no acaba de hacer:

bool greaterThan = x > 5; 
bool lessThan = x < 5; 

Una comparación booleana es ya una expresión ...

Editar:

Así que para su función, sólo tiene que pasar un bool: Editar

public void f(bool expression) 
{ 
    // expression is either true or false... 
} 

f(x<5); // called like this 
+0

La principal diferencia entre su respuesta y las otras respuestas en este hilo es _cuando_ se ejecuta la comparación. Su código se ejecuta inmediatamente, el otro código se ejecuta solo cuando se llama a 'expresión'. Esto puede ser útil si no siempre se necesita saber 'greaterThan' y' x' es costoso de computar. –

+0

Eso supone que 'x' es una llamada a función u otra expresión" demorada ". –

+0

Gracias por aclarar, no uso .NET 3.0, así que no estoy tan familiarizado con las expresiones lambda como debería ser –

0

: Supongamos que la expresión es una cadena, como "x < 2". ¿Hay alguna manera de pasar de la cadena a un predicado sin usar una serie de sentencias if sobre la condición?

Existen varios trucos que puede usar para convertir cadenas en código en .Net: CodeDom, Reflection.Emit, o incluso crear scripts del compilador en el shell. Sin embargo, ninguno de estos es tan simple como un eval() rápido en lenguajes de scripting, y esto generalmente está mal visto en .Net a menos que realmente sepa lo que está haciendo.

En su lugar,.Net proporciona el espacio de nombre System.Addin como una forma más segura de permitir extensiones de usuario a su aplicación.

2

Editar: Supongamos que la expresión es una cadena, como "x < 2". ¿Hay alguna manera de pasar de la cadena a un predicado sin usar una serie de sentencias if sobre la condición?

Como algunas personas ya han mencionado; si desea poder usar una cadena, necesita analizar. Realmente no desea escribir su propio analizador de C#, afortunadamente, algunas personas en Microsoft ya lo hicieron con Dynamic LINQ.

Aquí es una solución a su problema:

public void g() 
{ 
    int x = 0; 

    bool greaterThan = f("x > 2", x); 
    bool lessThan = f("x < 2", x); 
} 

public bool f(string expression, int x) 
{ 
    ParameterExpression xExpr = Expression.Parameter(typeof(int), "x"); 

    LambdaExpression e = DynamicExpression.ParseLambda(
     new ParameterExpression[] { xExpr }, typeof(bool), expression); 

    return (bool)e.Compile().DynamicInvoke(x); 
} 

Ahora, obviamente, esto va a explotar en el más mínimo error en la cadena. Realmente necesita estar pensando si realmente necesita esto. Pero si realmente lo hace, puede usar el método DynamicExpression.ParseLambda para analizar cadenas en LambdaExpression s.

+0

Realmente no necesito hacerlo, pero eso es increíble. Voy a tratar de salir. –

Cuestiones relacionadas