Linq Query Built in Foreach Loop Always Takes Parameter Value from Last Iteration

Linq query built in foreach loop always takes parameter value from last iteration

You're reusing the same variable (key) in your lambda expression.

See my article on anonymous methods for more details, and there are a number of related SO questions too:

  • LINQ to SQL bug (or very strange feature)...
  • Local variables with delegates
  • C# captured variable in a loop
  • C# gotcha answer
  • Building a LINQ query programmatically without local variables tricking me

The simple fix is to copy the variable first:

List<string> keys = FillKeys()
foreach (string key in keys){
string copy = key;
q = q.Where(c => c.Company.Name.Contains(copy));
}

Linq query built in foreach loop always takes parameter value from last iteration

You're reusing the same variable (key) in your lambda expression.

See my article on anonymous methods for more details, and there are a number of related SO questions too:

  • LINQ to SQL bug (or very strange feature)...
  • Local variables with delegates
  • C# captured variable in a loop
  • C# gotcha answer
  • Building a LINQ query programmatically without local variables tricking me

The simple fix is to copy the variable first:

List<string> keys = FillKeys()
foreach (string key in keys){
string copy = key;
q = q.Where(c => c.Company.Name.Contains(copy));
}

Building a LINQ query programmatically without local variables tricking me

(Edited for clarity.)

The problem is the foreach loop, and the fact that the "a" variable is being captured and then changed each time. Here's a modification which will work, by effectively introducing a "new" variable for each iteration of the loop, and capturing that new variable.

foreach (Attribute a in requiredAttributes)
{
Attribute copy = a;
result = result.Where(p => p.Attributes.Contains(copy));
}

Omer's solution is a cleaner one if you can use it, but this may help if your real code is actually more complicated :)

EDIT: There's more about the issue in this closures article - scroll down to "Comparing capture strategies: complexity vs power".

Foreach Iteration Null

Calling the value of a non existing attribute will cause a nullreference because the node simply doesn't exist.

child.Attribute("ows_ContentType").Value

throws an exception by calling the value of the missing element.

use this instead:

child.Attribute("ows_ContentType") != null

implemented:

IEnumerable<XElement> result = from child in root.Descendants(xns + "row")
where child.Attribute("ows_ContentType") != null && child.Attribute("ows_ContentType").Value == "Folder"
select child;

Building query in a loop with entity framework strange behaviour

Thanks Equiso, I didn't find the question you refered to. So this is an exact duplicate of Linq query built in foreach loop always takes parameter value from last iteration.

How do you get the index of the current iteration of a foreach loop?

The foreach is for iterating over collections that implement IEnumerable. It does this by calling GetEnumerator on the collection, which will return an Enumerator.

This Enumerator has a method and a property:

  • MoveNext()
  • Current

Current returns the object that Enumerator is currently on, MoveNext updates Current to the next object.

The concept of an index is foreign to the concept of enumeration, and cannot be done.

Because of that, most collections are able to be traversed using an indexer and the for loop construct.

I greatly prefer using a for loop in this situation compared to tracking the index with a local variable.

Can I use linq to achieve the same thing this foreach loop does?

Similar to some existing answers, but doing the projection in the query, to make the Sum call a lot simpler:

var sum = (from fee in loan.Items.Fees
where fee.Classification == 806
select fee.SomeValueToSum).Sum();

Can all 'for' loops be replaced with a LINQ statement?

Sure. Heck, you can replace arithmetic with LINQ queries:

http://blogs.msdn.com/ericlippert/archive/2009/12/07/query-transformations-are-syntactic.aspx

But you shouldn't.

The purpose of a query expression is to represent a query operation. The purpose of a "for" loop is to iterate over a particular statement so as to have its side-effects executed multiple times. Those are frequently very different. I encourage replacing loops whose purpose is merely to query data with higher-level constructs that more clearly query the data. I strongly discourage replacing side-effect-generating code with query comprehensions, though doing so is possible.



Related Topics



Leave a reply



Submit