开发者

Linq Collection gets reset on next iteration of foreach

I have the following foreach expression within which I am building a predicate 开发者_高级运维and then filtering the collection by executing .Where().

But what stumps me is, result.Count() gives me 0 even before I execute .Where() in the next iteration.

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

Does, anybody know of any LINQ behavior that I might have overlooked that is causing this?


I think, you want this:

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

Notice the use of f in the predicate. You don't want to capture the foreach variable. In your original code, when the second iteration starts, param is still the captured value from the first iteration, but fieldName has changed.


I agree that the issue comes from not capturing the foreach variable, but there is a deeper issue and that is the combination of LINQ with imperative control flow structures - i.e. mixing LINQ & foreach in the first place.

Try this instead:

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

No foreach loop needed and the code stays purely in LINQ. Friends shouldn't let friends mix imperative and functional... :-)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜