хорошо, ребята, голые со мной. Сначала я подведу итоги, а затем подробно расскажу.
Я написал несколько методов (.WhereOr, .WhereAnd), которые в основном позволяют мне «складывать» кучу лямбда-запросов, а затем применять их к коллекции. Например, использование с наборами данных было бы немного похоже на это (хотя это работает с любым классом с использованием обобщений):
С LINQ TO DATASETS (с использованием .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();
Теперь скажите, что в приведенном выше примере только одна строка в коллекции соответствует "somestring" и находится в поле "field2".
Это означает, что значение Result должно быть равно 1.
Теперь, скажем, я немного переписал код выше к этому:
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();
Я не очень понимаю выражения, но для меня оба приведенных выше примера делают одно и то же.
За исключением того, что "Result" в первом примере имеет счетчик 1, а "Result" во втором примере имеет счетчик 0.
Кроме того, в столбцах списка во втором примере, если вы поставите «field2» последним, а не вторым, тогда «Result» правильно будет иметь счет 1.
Итак, из всего этого я пришел к какому-то выводу, но я не совсем понимаю, что происходит, и как это исправить ..? Могу ли я «оценить» эти выражения раньше ... или их часть?
ВЫВОД:
По сути, кажется, что если я посылаю туда буквальные значения, например, "field1", это работает. Но если я отправлю переменные, такие как «col», это не сработает, потому что эти «выражения» оцениваются намного позже в коде.
это также объясняет, почему это работает, когда я перемещаю «field2» в последнюю позицию. это работает, потому что переменная "col" была наконец назначена "field2", таким образом, к тому времени, когда выражения оценивают "col", равно "field2".
Ладно, есть ли способ обойти это?
Вот код для моего метода WhereOr (это метод расширения 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);
}