最快的单元迭代方法

本文关键字:迭代 方法 单元 | 更新日期: 2023-09-27 18:25:30

我有一个DataGridView,在实践中,它可能有多达2000行和100列。我想遍历所有单元格,并根据单元格中底层数据的性质,将内容添加到列表中。当前代码如下:

for (var columnIndex = 1; columnIndex < edgv.ColumnCount; columnIndex++)
{
    for (var rowIndex = 1; rowIndex < edgv.RowCount; rowIndex++)
    {
        var currentValue = edgv[columnIndex, rowIndex].Value as ISomeInterface;
        if (currentValue != null && (currentValue.GetType().Equals(typeof(SomeClass).FullName)) 
            && (((SomeClass)currentValue).Attribute != null))
        {
            values.Add(currentValue);
        }
    }
}

这段代码适用于较小的网格,但当ColumnCount和RowCount开始变大时,它似乎会陷入困境(如果不是完全停滞的话)。我想知道将for循环改为foreach循环是否会有所帮助,我对其他想法持开放态度。

有什么想法吗?

最快的单元迭代方法

改进现有流程性能的第一步通常应该是评测。探查器会告诉你哪段代码最耗时,让你知道哪段代码需要优化。很多时候,瓶颈就在你最意想不到的地方,如果没有探查器,你可能会在优化代码上浪费很多时间,这将使你几乎没有实际的性能改进。

现在,我将忽略我在上一段中所说的内容,给出一些建议:

  1. 您没有共享创建values集合的位置的代码。假设它是一个List,它有一个获取容量参数的构造函数。这对性能非常重要。如果使用空构造函数,默认容量为5,如果在集合中插入大量值,这可能会对场景中的性能造成灾难性影响。原因是list在内部实现为长度为"capacity"的数组,每当您插入长度超过该长度的项时,它都会创建一个长度为该长度两倍的新数组(现在将是新容量),并将所有项从旧数组复制到新数组。复制过程会影响性能。此外,必须始终分配新数组(并丢弃旧数组)会导致GC运行amoc,还会导致内存碎片,所有这些都可能是代码中的潜在瓶颈。因此,在创建列表时,您应该选择适当的容量。在最常见的情况下,您应该根据您对列表中项目数量的估计来选择容量。例如,如果您希望通常插入几乎所有的单元格,则可以调用:values = new List<SomeClass>(edgv.ColumnCount * edgv.RowCount);

  2. 注释中已经说过,但在每个单元格迭代中,您先转换为ISomeInterface,然后再转换为SomeClass。由于您并没有真正使用ISomeInterface,因此这是多余的。只要选角到SomeClass就足够了,并且可能会提高您的性能。

        for (var columnIndex = 1; columnIndex < edgv.ColumnCount; columnIndex++)
        {
            for (var rowIndex = 1; rowIndex < edgv.RowCount; rowIndex++)
            {
                var currentValue = edgv[columnIndex, rowIndex].Value as SomeClass;
                if (currentValue != null && currentValue.Attribute != null)
                {
                    values.Add(currentValue);
                }
            }
        }
    
  3. 评论中也提到,您可能不需要迭代所有单元格。通常在轴网中,每列的类型都是相同的。如果您的情况也是如此,那么您可以检查每列中的第一个单元格,并根据其类型避免检查该列中的其他单元格。

        for (var columnIndex = 1; columnIndex < edgv.ColumnCount; columnIndex++)
        {
            for (var rowIndex = 1; rowIndex < edgv.RowCount; rowIndex++)
            {
                var currentValue = edgv[columnIndex, rowIndex].Value as SomeClass;
                if (currentValue == null) break; //Skipping the check for this column
                if (currentValue.Attribute != null)
                {
                    values.Add(currentValue);
                }
            }
        }