I observe a very strange behavior, maybe could you help me to see what happen.
Here the class:
public sealed class Sudoku
{
private SudokuCell[] _grid = new SudokuCell[81];
// ctor {}
private IEnumerable<SudokuCell> Grid
{
get { return _grid; }
}
private SudokuRow[] _rows;
public IEnumerable<SudokuRow> Rows
{
get
{
if (_rows == null)
{
_rows = new SudokuRow[9];
for (int i = 0, length = 9; i < length; i++)
{
_rows[i] = new SudokuRow(from cell in Grid
where cell.Row == i
select cell);
// Always print 9 (GOOD)
Trace.WriteLine("First Loop " + i + " : " + _rows[i].Cells.Count());
}
}
for (int i = 0; i < 9; i++)
{
// Always print 0 ! Huh !?
Trace.WriteLine("Second Loop " + i + " : " + _rows[i].Cells.Count());
}
return _rows;
}
}
}
public abstract class SudokuPart
{
public SudokuPart(IEnumerable<SudokuCell> cells)
{
Cells = cells;
}
public int Index
{ get; protected set; }
public IEnumerable<SudokuCell> Cells
{ get; protected set; }
}
public sealed class SudokuRow : SudokuPart
{
public SudokuRow(IEnumerable<SudokuCell> cells)
: base(cells)
{
base.Index = cells.First().Row;
}
}
Could anyone tell me why in the second loop it trace 0 instead of 9 !? I changed nothing between both loops !!!
Thanks…
This is the problem:
That’s capturing the loop variable (
i)… within the loop, it has a sensible value, which is why you’re seeing 9 matches.However, when you count the matching values in the second loop, that single captured variable will have the value 9. Now no
cell.Rowhas a value of 9, so you’re not getting any matches. For more information on this, see Eric Lippert’s great blog post, “Closing over the loop variable considered harmful.”Three fixes:
Capture a copy of the loop variable:
Each iteration of the loop will get a separate copy.
Materialize the query in the loop:
Or even:
Don’t use LINQ at all! Why not just have an array of arrays to represent the grid? That’s a much more natural approach, IMO.