Коллекция Linq сбрасывается при следующей итерации foreach - PullRequest
2 голосов
/ 24 августа 2011

У меня есть следующее foreach выражение, в котором я создаю предикат и затем фильтрую коллекцию, выполняя .Where().

Но что меня озадачивает, так это result.Count() дает мне 0 еще до того, как я выполню .Where() в следующей итерации.

var result = SourceCollection;

foreach (var fieldName in FilterKeys)
{
    if (!conditions.ContainsKey(fieldName)) continue;
    if (!conditions[fieldName].IsNotNullOrEmpty()) continue;
    var param = conditions[fieldName];
    Func<BaseEntity, bool> predicate = (d) => fieldName != null && d.GetFieldValue(fieldName).ContainsIgnoreCase(param);
    result =  result.Where(predicate);
}

Кто-нибудь знает о каком-либо поведении LINQ, которое я мог упустить из виду, которое вызывает это?

Ответы [ 2 ]

6 голосов
/ 24 августа 2011

Я думаю, вы хотите это:

var result = SourceCollection;

foreach (var fieldName in FilterKeys)
{
    if (!conditions.ContainsKey(fieldName)) continue;
    if (!conditions[fieldName].IsNotNullOrEmpty()) continue;
    var param = conditions[fieldName];
    var f = fieldName
    Func<BaseEntity, bool> predicate = (d) => f != null && d.GetFieldValue(f).ContainsIgnoreCase(param);
    result =  result.Where(predicate);
}

Обратите внимание на использование f в предикате.Вы не хотите захватывать переменную foreach.В исходном коде, когда начинается вторая итерация, param по-прежнему является захваченным значением первой итерации, но fieldName изменилось.

3 голосов
/ 24 августа 2011

Я согласен с тем, что проблема заключается не в захвате переменной foreach, но есть более глубокая проблема, которая заключается в сочетании LINQ с императивными структурами потоков управления - то есть, во-первых, смешиванием LINQ & foreach.

Попробуйте вместо этого:

var predicates =
    from fieldName in FilterKeys
    where conditions.ContainsKey(fieldName)
    let param = conditions[fieldName]
    where param.IsNotNullOrEmpty()
    select (Func<BaseEntity, bool>)
        (d => fieldName != null
              && d.GetFieldValue(fieldName).ContainsIgnoreCase(param));

var result = predicates.Aggregate(
    SourceCollection as IEnumerable<BaseEntity>,
    (xs, p) => xs.Where(p));

Нет необходимости в цикле foreach, и код остается чисто в LINQ.Друзья не должны позволять друзьям смешивать императив и функциональность ...: -)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...