Comparación de cadenas de árbol de expresión Linq

expression-trees linq

Pregunta

Estoy tratando de construir un árbol de expresiones para operar contra una matriz de cadenas. Necesito averiguar cómo usar el método Equal.

¿Podría alguien darme un ejemplo de
1) utilizando el método Expression.Equal (o .Equals) para comparar una cadena con una constante, y
2) utilizando una expresión de cualquier tipo para usar el método string.Contains () con fines de filtrado.

Estoy tratando de aprender la mecánica del árbol de expresiones, pero hasta ahora no he encontrado un buen tutorial. Aprecio mucho tu ayuda.

string[] arr = {"s1","s2","s3"};
IQueryable<String> queryableData = arr.AsQueryable<string>();

// what should go below here?
ParameterExpression p1 = Expression.Parameter(typeof(string), "c");
Expression left = Expression.Constant("s2");
Expression e1 = Expression.Equal(left, p1);

IQueryable<string> res = queryableData.Provider.CreateQuery<string>(e2);

Respuesta aceptada

Aaah, veo lo que estás preguntando ... Y realmente estás entrando en algunas aguas muy turbias, una de las pocas áreas con las que las bibliotecas de reflexión .NET no son hermosas para trabajar. Debe crear una expresión de llamada para llamar a Queryable.Where () en el objeto queryableData y crear una nueva consulta con esa expresión ... El problema es que obtener una versión genérica de un método en .NET no es necesariamente la más fácil cosa que has encontrado en tu vida:

MethodCallExpression call = Expression.Call(
    null, // Calling Queryable.Where(), extension method, not instance method
    getGenericMethod<string>(typeof(Queryable), "Where", typeof(IQueryable<string>), typeof(Expression<Func<string,bool>>)),
    Expression.Constant(queryableData),
    Expression.Lamda(
       e1,
       p1)
);
IQueryable<string> res = queryableData.Provider.CreateQuery<string>(call);

También tendría que definir getGenericMethod (puede encontrar mejores implementaciones para esto en línea en otros lugares, esto es realmente un enfoque bastante simple):

private static MethodInfo getGenericMethod<T>(Type type, string name, params Type[] paramTypes)
{
    MethodInfo[] methods = type.GetMethods(name);
    foreach(MethodInfo mi in methods)
    {
        if(!mi.IsGenericMethodDefinition) // or some similar property
            continue;
        if(mi.GetGenericArguments().Length != 1)
            continue;
        if(mi.GetParameters().Length != paramTypes.Length)
            continue;


        MethodInfo genMethod = mi.MakeGenericMethod(new Type[]{typeof(T)});
        var ps = genMethod.GetParameters();
        bool isGood = true;
        for(int i = 0; i < ps.Length; i++)
        {
            if(ps[i].ParameterType != paramTypes[i])
            {
               isGood = false;
               break;
            }
        }

        if(isGood)
            return genMethod;

    }

    return null;
}

Sin duda hay algunos errores, pero espero que puedan ver a dónde ir desde allí ...


Respuesta popular

Solo para dar mi solución:

string[] arr = {"s1","s2","s3"};
IQueryable<String> queryableData = arr.AsQueryable<string>();
ParameterExpression pe = Expression.Parameter(typeof(string), "company");
Expression right = Expression.Constant("on");
Expression left = Expression.Call(pe, typeof(string).GetMethod("Contains"), right);
MethodCallExpression e2 = Expression.Call(
            typeof(Queryable),
            "Where",
            new Type[] { queryableData.ElementType },
            queryableData.Expression,
            Expression.Lambda<Func<string, bool>>(left, new ParameterExpression[] { pe }));

IQueryable<string> res = queryableData.Provider.CreateQuery<string>(e2);


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