Technical inside : why does this iteration not find my item
Hey people yesterday i was working on some code and thought that i would save a foreach iteration and use the find extension on the List<> object, but i never got it to work. later i refactored the the code to use a foreach with a lamda where statement and that found my item evrytime.
my 2 versions of code are posted below:
Not working version:
private XmlCell FindCell(string id)
{
XmlSection section = new XmlSection(SectionNode);
XmlCell currentCell = null;
foreach (XmlBlock block in section.Blocks)
{
foreach (XmlRow row in block.Rows)
{
currentCell = row.Cells.Find(cell => string.Equals(cell.Id, id));
}
}
Assert.IsNotNull(currentCell, string.Format("Cell with id {0} not found", id));
return currentCell;
}
working version :
XmlSection section = new XmlSection(SectionNode);
XmlCell currentCell = null;
foreach (XmlBlock block in section.Blocks)
{
foreach (XmlRow row in block.Rows)
{
foreach (XmlCell cell in row.Cells.Where(cell => string.Equals(cell.Id, id)))
{
return cell;
}
}
}
Assert.IsNotNull(currentCell, string.Format("Cell with id {0} not found", id));
return currentCell;
could someone plx explain why the first bit of code dont get the job done, msdn says that the find method returns the开发者_开发问答 first instance it finds in the list.
i even encountered some "Collection was modified; enumeration operation may not execute" errors, why ?
Because the next iteration will make your variable currentCell
null again when Find
didn't find the cell with the matching ID. In the second piece of code you return the found cell immediately.
In the first piece of code try this:
foreach (XmlRow row in block.Rows)
{
currentCell = row.Cells.Find(cell => string.Equals(cell.Id, id));
//new
if (currentCell != null)
return currentCell;
//end new
}
When you find your cell with the specified ID, the currentCell
is set to this specific object. However, on the next iteration in the foreach loop, currentCell
is set to nothing, because Find
returns nothing :)
foreach (XmlRow row in block.Rows)
{
currentCell = row.Cells.Find(cell => string.Equals(cell.Id, id));
}
The 2 versions of code are different - second one returns from all nested loops as soon as it finds a matching cell, while first one returns presence of the cell in the last row of the last block.
Fix - add check for finding the cell in inner loop and retrun as soon one found:
foreach (XmlBlock block in section.Blocks)
{
foreach (XmlRow row in block.Rows)
{
currentCell = row.Cells.FirstOrDefault(cell => string.Equals(cell.Id, id));
if (currentCell != null)
return currentCell;
}
}
精彩评论