奇怪的数组行为

本文关键字:数组 | 更新日期: 2023-09-27 18:08:31

我观察到一个很奇怪的行为,也许你能帮我看看是怎么回事吗

这里的类:

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;
    }
}
谁能告诉我为什么在第二个循环中它跟踪0而不是9 !?我在两个循环之间没有改变任何东西!!

谢谢…

奇怪的数组行为

这就是问题所在:

_rows[i] = new SudokuRow(from cell in Grid
                         where cell.Row == i
                         select cell);

这是捕获循环变量(i)…循环中,它有一个合理的值,这就是为什么您看到9个匹配。

但是,当您在第二个循环中计算匹配值时,单个捕获的变量的值将为9。现在no cell.Row的值为9,所以您没有得到任何匹配。有关这方面的更多信息,请参阅Eric Lippert的伟大博客文章"关闭被认为有害的循环变量"。

三个补丁:

  • 捕获循环变量的副本:

    int copy = i;
    _rows[i] = new SudokuRow(from cell in Grid
                             where cell.Row == copy
                             select cell);
    
  • 在循环中实现查询:

    _rows[i] = new SudokuRow((from cell in Grid
                             where cell.Row == i
                             select cell).ToList());
    

    甚至:

    _rows[i] = new SudokuRow(Grid.Where(cell => cell.Row == i).ToList());
    
  • 不要使用LINQ !为什么不直接用数组的数组来表示网格呢?这是一种更自然的方法,IMO。

我认为Jon Skeet的回答很好,但我只是想用一个延迟LINQ查询的例子来添加一点。当我看到实际情况时,它帮助我更多地理解了您遇到的这类代码问题的一些细微差别。

试试这段代码。

var numbers = new List<int> {1, 2, 3, 4, 5};
//Lets create an IEnumerable<int> with the values in our numbers list greater then 3.
var bignumbers = numbers.Where(n => n > 3);
//You may assume our variable bignumbers now contains the numbers 4 and 5
//now lets add another number to our original list that fits the criteria of our LINQ Where statement   
numbers.Add(6);

foreach (var big in bignumbers) {
  Console.WriteLine(big.ToString());
}

foreach循环的输出将是4,5,6!这是因为直到foreach导致bignnumbers变量中的项枚举时,查询才运行。

只是当你在循环内构建列表和在循环外查询这些列表时要考虑的另一个问题。