Combinare più espressioni (espressione >) non funziona con le variabili. Perché?

expression-trees foreach lambda linq

Domanda

ok ragazzi, nudi con me. Prima riassumerò, poi andrò nei dettagli.

Ho scritto un certo numero di metodi (.WhereOr, .WhereAnd) che fondamentalmente mi permettono di "accatastare" un mucchio di query lambda e quindi applicarle a una raccolta. Ad esempio, l'utilizzo con set di dati sarebbe un po 'come questo (sebbene funzioni con qualsiasi classe usando i generici):

CON LINQ A DATASET (Utilizzo di .NET DataSetExtensions)

DataTable Result;

List<Expression<Func<DataRow, bool>> Queries = new List<Expression<Func<DataRow, bool>>();

Queries.Add(dr=> dr.Field<string>("field1") == "somestring");
Queries.Add(dr=> dr.Field<string>("field2") == "somestring"); 
Queries.Add(dr=> dr.Field<string>("field3") == "somestring"); 

Result = GetSomeTable().AsEnumarable().WhereOr(Queries).CopyToDataTable();

Ora dì che nell'esempio sopra solo una riga nella collezione corrisponde a "somestring", ed è sul campo "field2".

Ciò significa che il conteggio per Risultato dovrebbe essere 1.

Ora, diciamo che riscrivo leggermente il codice sopra a questo:

DataTable Result;

List<Expression<Func<DataRow, bool>> Queries = new List<Expression<Func<DataRow, bool>>();

List<string> columns = new string[]{"field1","field2","field3"}.ToList();

string col;

foreach(string c in columns){
    col = c;
    Queries.Add(dr=> dr.Field<string>(col) == "somestring");
}

Result = GetSomeTable().AsEnumarable().WhereOr(Queries).CopyToDataTable();

Ora, non capisco davvero le espressioni, ma per me entrambi gli esempi sopra stanno facendo esattamente la stessa cosa.

Tranne che "Risultato" nel primo esempio ha un conteggio di 1, e "Risultato" nel secondo esempio ha un conteggio di 0.

Inoltre, nelle colonne Elenco del secondo esempio, se si inserisce "campo2" per ultimo, anziché per secondo, "Risultato" ha correttamente un conteggio pari a 1.

Quindi, da tutto questo sono arrivato a una specie di conclusione, ma non capisco davvero cosa sta succedendo, né come risolverlo ..? Posso "valutare" quelle espressioni prima ... o parte di esse?

CONCLUSIONE:

In sostanza, sembra che se mando valori letterali lì, come "field1", funzioni. Ma se invio variabili, come "col", non funziona, perché quelle "espressioni" vengono solo valutate molto più tardi nel codice.

questo spiegherebbe anche perché funziona quando sposto "field2" nell'ultima posizione. funziona perché la variabile "col" è stata assegnata infine a "field2", quindi nel momento in cui le espressioni valutano "col" è uguale a "field2".

Ok, allora, c'è un modo per aggirare questo?

Ecco il codice per il mio metodo WhereOr (è un metodo di estensione per IENumerable):

public static IQueryable<T> WhereOr<T>(this IEnumerable<T> Source, List<Expression<Func<T, bool>>> Predicates) {

        Expression<Func<T, bool>> FinalQuery;

        FinalQuery = e => false;

        foreach (Expression<Func<T, bool>> Predicate in Predicates) {
            FinalQuery = FinalQuery.Or(Predicate);
        }

        return Source.AsQueryable<T>().Where(FinalQuery);
    }

public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> Source, Expression<Func<T, bool>> Predicate) {
        InvocationExpression invokedExpression = Expression.Invoke(Predicate, Source.Parameters.Cast<Expression>());
        return Expression.Lambda<Func<T, bool>>(Expression.Or(Source.Body, invokedExpression), Source.Parameters);
    }

Risposta accettata

La risposta "come risolvere". Cambia questo:

string col;
foreach(string c in columns) {
    col = c;
    Queries.Add(dr=> dr.Field<string>(col) == "somestring");
} 

a questa:

foreach(string c in columns) {
    string col = c;
    Queries.Add(dr=> dr.Field<string>(col) == "somestring");
} 

Godere. La risposta "what & why" è stata data da Brian.


Risposta popolare



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é