最快的细胞迭代方法

时间:2015-12-03 20:07:16

标签: c# winforms datagridview

我有一个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 个答案:

答案 0 :(得分:0)

提高现有流程性能的第一步通常应该是分析。分析器会告诉您哪段代码需要花费最多的时间,让您知道哪一块需要优化。很多时候瓶颈是你最不期望的地方,如果没有分析器,你可能会浪费大量时间来优化代码,这将使你的实际性能提高接近于零。

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

  1. 您没有分享创建values集合的代码。假设它是List,它有一个获取容量参数的构造函数。这对性能非常重要。如果使用空构造函数,则默认容量为5,如果向集合中插入大量值,则对于场景中的性能可能是灾难性的。 这样做的原因是列表在内部实现为一个容量数组&#39;长度,每当您在长度上方插入一个项目时,它将创建一个长度为两倍的新数组(现在将是新容量),并将旧数组中的所有项目复制到新数组。 复制过程会损害性能。还必须始终分配新数组(并删除旧数组)将导致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);
                }
            }
        }