ok les gars, nues avec moi. Je résumerai d'abord, puis entrerai dans les détails.Combinaison de plusieurs expressions (Expression <Func<T,bool>>) ne fonctionnant pas avec des variables. Pourquoi?
J'ai écrit un certain nombre de méthodes (.WhereOr, .WhereAnd) qui me permettent fondamentalement d'empiler un tas de requêtes lambda, puis de les appliquer à une collection. Par exemple, l'utilisation des ensembles de données serait un peu comme ça (même si cela fonctionne avec une classe en utilisant les génériques):
AVEC LINQ À DATASETS (À l'aide des DataSetExtensions .NET)
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();
maintenant dire que dans l'exemple ci-dessus, une seule ligne de la collection correspond à "somestring", et c'est sur le champ "field2".
Cela signifie que le compte pour résultat devrait être 1.
Maintenant, je dis ré-écrire le code ci-dessus un peu à ceci:
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();
Maintenant, je ne comprends pas vraiment expressions, mais pour moi les deux exemples ci-dessus font exactement la même chose.
Sauf que « Résultat » dans le premier exemple a un compte de 1 et « Résultat » dans le second exemple a un compte de 0.
En outre, dans la liste des colonnes dans le second exemple, si vous mettre "field2" en dernier, au lieu de second, alors "Result" a correctement le compte de 1.
Donc, de tout ceci je suis arrivé à une sorte de conclusion, mais je ne comprends pas vraiment ce qui se passe , ni comment le réparer ..? Puis-je "évaluer" ces expressions plus tôt ... ou en faire partie?
CONCLUSION:
En fait, il semble que, si j'envoie des valeurs littérales en là, comme "field1", cela fonctionne. Mais si j'envoie des variables, comme "col", cela ne fonctionne pas, car ces "expressions" ne sont évaluées que plus tard dans le code.
cela expliquerait aussi pourquoi cela fonctionne quand je déplace "field2" à la dernière position. cela fonctionne parce que la variable "col" a été affectée à "field2" enfin, donc au moment où les expressions évaluent "col" est égal à "field2".
Ok, donc, y a-t-il un moyen de contourner cela?
Voici le code pour ma méthode de WhereOr (il est une méthode d'extension pour 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);
}
Essayez de prendre l'expression finale que vous avez construit dans chaque sens et de faire « ToString » à elle. Vous obtiendrez une version joliment imprimée de l'expression que je trouve souvent utile lors de la construction dynamique des arbres d'expression. Vous devriez également google LinqKit, une bibliothèque qui fournit beaucoup de méthodes d'aide pour manipuler les arbres d'expression. –