Analizar la condición booleana en el árbol de expresión

c# expression-trees linq

Pregunta

Si tengo un método que toma un booleano como:

public void Foo(boolean condition)

Y llámalo así:

Foo("MyField" == "MyValue");

¿Puedo componer eso en un árbol de expresiones para construir una consulta a alguna otra fuente de datos que usará MyField como un parámetro y MyValue y otro? Parece que solo puedo convertir esa condición en una expresión que se evalúa como falsa.

ACTUALIZAR

    var param = Expression.Parameter(typeof(Field), field);
    var prop = Expression.PropertyOrField(param, "Name");

    ConstantExpression @const = Expression.Constant(value, typeof(string));
    var body = Expression.Equal(prop, @const);
    var lambda = Expression.Lambda<Func<Field, bool>>(body, param);

Donde Field es una clase con dos propiedades, Nombre y Valor

Respuesta aceptada

Foo("MyField" == "MyValue") es, como se indica en la parte inferior de la pregunta, una constante false (derecha en el compilador). Aquí tiene algunas opciones; lo más simple, por supuesto, es hacer algo como:

void Foo(Expression<Func<YourType,bool>> predicate) {...}

y llamar con

Foo(x => x.MyField == "MyValue");

entonces aquí , no queda nada por hacer; Ya tenemos la expresión. Entonces supongo que te refieres a que "MyField" es una cadena que solo se conoce en tiempo de ejecución, en cuyo caso:

void Foo<T>(string fieldName, T value) {
   var param = Expression.Parameter(typeof(YourType), "x");
   var body = Expression.Equal(
                  Expression.PropertyOrField(param, fieldName),
                  Expression.Constant(value, typeof(T))
               );
   var lambda = Expression.Lambda<Func<YourType, bool>>(body, param);
}

y llame con Foo("MyField", "MyValue) (con una <string> implícita allí, cortesía del compilador), o Foo("MyField", 123) si la prop es una int ( <int> implícita),

El escenario final es donde "MyValue" también es una cadena que solo se conoce en tiempo de ejecución (emph: string ), en cuyo caso deberemos analizarla:

void Foo(string fieldName, string value) {
   var param = Expression.Parameter(typeof(YourType), "x");
   var prop = Expression.PropertyOrField(param, fieldName);
   ConstantExpression @const;
   if(prop.Type == typeof(string)) {
       @const = Expression.Constant(value, typeof(string));
   } else {
       object parsed = TypeDescriptor.GetConverter(prop.Type)
           .ConvertFromInvariantString(value);
       @const = Expression.Constant(parsed, prop.Type);
   }
   var body = Expression.Equal(prop,@const);
   var lambda = Expression.Lambda<Func<YourType, bool>>(body, param);
}

Aquí la llamada siempre es de 2 cadenas, por lo que Foo("MyField", "123") incluso cuando int .


Respuesta popular

En puede crear árboles de expresión de delegados. Por ejemplo, si define su método para que tome un delegado como parámetro, puede usarlo de la siguiente manera:

public void Foo(Func<bool> fn)
{
    // invoke the passed delegate
    var result = fn();
}

Foo(() => "MyField" == "MyValue");

Para crear un árbol de expresiones, en lugar de ejecutar el delegado, cambie el método de la siguiente manera:

public void Foo(Expression<Func<bool>> expression)
{
   // inspect your expression tree here
}

Sin embargo, en su caso, encontrará que su expresión es una constante booleana con un valor de 'falso', esto se debe a que el compilador ha evaluado "MyField" == "MyValue" que por supuesto es falso.

¿Si solo quiere pares nombre-valor, que no solo usan un Dictionary<string, string> ?



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow