Confronto tra le stringhe dell'albero delle espressioni di Linq

expression-trees linq

Domanda

Sto cercando di costruire un albero di espressioni per operare contro un array di stringhe. Devo capire come usare il metodo Equal.

Qualcuno potrebbe darmi un esempio di
1) usando il metodo Expression.Equal (o .quals) per confrontare una stringa con una costante, e
2) utilizzando un'espressione di qualsiasi tipo per utilizzare il metodo string.Contains () per scopi di filtraggio.

Sto cercando di imparare la meccanica di Expression Tree, ma fino ad ora non ho trovato un buon tutorial. Apprezzo molto il tuo aiuto.

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

Risposta accettata

Aaah, vedo cosa stai chiedendo ... E stai davvero entrando in acque molto torbide, una delle poche aree in cui le librerie di riflessioni .NET non sono belle con cui lavorare. Devi creare un'espressione di chiamata per chiamare Queryable.Where () sull'oggetto queryableData e creare una nuova query usando quell'espressione ... Il problema è che ottenere una versione generica di un metodo in .NET non è necessariamente la più semplice cosa hai mai incontrato nella tua vita:

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

Dovresti anche definire getGenericMethod (puoi trovare implementazioni migliori per questo online in altri posti, questo è davvero un approccio molto semplice):

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

Ci sono quasi indubbiamente alcuni errori, ma spero che tu possa vedere da dove andare ...


Risposta popolare

Solo per dare la mia soluzione:

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


Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché