Construyendo dinámicamente un árbol de expresiones.

c# expression-trees linq

Pregunta

Estoy siguiendo este excelente ejemplo: Convertir Linq a Sql Expression a Expression Tree

En mi caso, estoy tratando de construir un árbol de expresiones en el que el tipo que se filtre solo se conozca en el tiempo de ejecución y se exprese como una cadena. En el ejemplo anterior, el tipo Región ya se conoce y se escribe directamente:

ParameterExpression pe = Expression.Parameter(typeof(Region), "region");

En mi aplicación he podido reescribir esto como:

ParameterExpression pe = Expression.Parameter(Type.GetType("mystring"), "listData");

Mi tropiezo es esto del ejemplo:

MethodCallExpression whereCallExpression = Expression.Call(
            typeof(Queryable),
            "Where",
            new Type[] { query.ElementType },
            query.Expression,
            Expression.Lambda<Func<Region, bool>>(e3, new ParameterExpression[] { pe }));
var results = query.Provider.CreateQuery<Region>(whereCallExpression);

En estas dos líneas Región se escribe directamente. ¿Hay una forma de usar dinámicamente una cadena "Región" para lograr lo mismo?

Respuesta aceptada

Claro, pero tendrás que entender las implicaciones. La Region nombre de tipo es el tipo de tiempo de compilación. Con él, puedes generar una consulta fuertemente tipada. Sin embargo, dado que no tiene el tipo en tiempo de compilación, aún puede generar una consulta, pero no se escribirá con fuerza.

Puede generar una expresión lambda de tipo de tiempo de compilación desconocido utilizando las sobrecargas no genéricas. Igualmente con el método CreateQuery() .

Aquí hay dos versiones de la misma consulta que verifica si algún valor de propiedad coincide con un valor dado. Uno es genérico y el otro no.

La versión genérica toma implícitamente el tipo del tipo de la consulta.

public IQueryable<TSource> PropertyEqualsValue<TSource>(IQueryable<TSource> query,
        string propertyName, object value)
{
    var param = Expression.Parameter(typeof(TSource));
    var body = Expression.Equal(
        Expression.Property(param, propertyName),
        Expression.Constant(value)
    );
    var expr = Expression.Call(
        typeof(Queryable),
        "Where",
        new[] { typeof(TSource) },
        query.Expression,
        Expression.Lambda<Func<TSource, bool>>(body, param)
    );
    return query.Provider.CreateQuery<TSource>(expr);
}
var query = PropertyEqualsValue(SomeTable, "SomeColumn", "SomeValue");

Mientras que el otro, el tipo se toma del typeName proporcionado. Tenga en cuenta que cuando se crea la consulta, no podemos proporcionar el tipo, ya que no sabemos cuál es el tipo en el momento de la compilación.

public IQueryable PropertyEqualsValue(IQueryable query,
        Type type, string propertyName, object value)
{
    var param = Expression.Parameter(type);
    var body = Expression.Equal(
        Expression.Property(param, propertyName),
        Expression.Constant(value)
    );
    var expr = Expression.Call(
        typeof(Queryable),
        "Where",
        new[] { type },
        query.Expression,
        Expression.Lambda(body, param)
    );
    return query.Provider.CreateQuery(expr);
}
var type = Type.GetType("Some.Type.Name");
var query = PropertyEqualsValue(SomeTable, type, "SomeColumn", "SomeValue");


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