最快的单元迭代方法
本文关键字:迭代 方法 单元 | 更新日期: 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循环是否会有所帮助,我对其他想法持开放态度。
有什么想法吗?
改进现有流程性能的第一步通常应该是评测。探查器会告诉你哪段代码最耗时,让你知道哪段代码需要优化。很多时候,瓶颈就在你最意想不到的地方,如果没有探查器,你可能会在优化代码上浪费很多时间,这将使你几乎没有实际的性能改进。
现在,我将忽略我在上一段中所说的内容,给出一些建议:
-
您没有共享创建
values
集合的位置的代码。假设它是一个List
,它有一个获取容量参数的构造函数。这对性能非常重要。如果使用空构造函数,默认容量为5,如果在集合中插入大量值,这可能会对场景中的性能造成灾难性影响。原因是list在内部实现为长度为"capacity"的数组,每当您插入长度超过该长度的项时,它都会创建一个长度为该长度两倍的新数组(现在将是新容量),并将所有项从旧数组复制到新数组。复制过程会影响性能。此外,必须始终分配新数组(并丢弃旧数组)会导致GC运行amoc,还会导致内存碎片,所有这些都可能是代码中的潜在瓶颈。因此,在创建列表时,您应该选择适当的容量。在最常见的情况下,您应该根据您对列表中项目数量的估计来选择容量。例如,如果您希望通常插入几乎所有的单元格,则可以调用:values = new List<SomeClass>(edgv.ColumnCount * edgv.RowCount);
-
注释中已经说过,但在每个单元格迭代中,您先转换为
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); } } }
-
评论中也提到,您可能不需要迭代所有单元格。通常在轴网中,每列的类型都是相同的。如果您的情况也是如此,那么您可以检查每列中的第一个单元格,并根据其类型避免检查该列中的其他单元格。
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); } } }