首页 > 解决方案 > VBA 类性能

问题描述

我有这个代码:

For i = 0 To .Fields.Count - 1
    Set qc = qcolumns(i)
    If qc.XlGrouped = True Then
...

对我来说奇怪的是,如果我改变qc.XlGrouped = Trueqcolumns(i).XlGrouped = True需要 200 毫秒,而第一个需要 0 毫秒。为什么与将类从数组设置为变量有如此大的区别?

标签: vba

解决方案


200ms 是轶事,但可以解释开销。

Dim qcolumns As Variant

那是你的数组,但对于 VBA 它只是一个Variant:为了知道它正在查看一个数组,VBA 需要(在运行时)取消引用变体指针,检查保存子类型元数据的字节,获取数组指针,......并取消引用数组指针。

显式数组声明的开销会更少:

Dim qcolumns(1 To 10) As SettingsColumns

现在,我们并不真正关心数组......我们只是试图迭代它的内容:

Set qc = qcolumns(i)

所以在每次迭代中,变体/数组解引用需要发生,并且对象指针被复制到qc. 但是为什么打会员电话要慢qcolumns(i)呢?

因为qcolumns是 a Variant,所以对它进行的任何成员调用都必须是后期绑定的,即在运行时解决。XlGrouped在成员调用成功之前,VBA 不知道该属性,并且成员调用只有在查询IUnknown对象的接口后才能成功(如果失败,则会引发错误 438)。

当你这样做时Dim qc As SettingsColumn,你会在编译时尽早绑定。现在编译器已经知道在哪里可以找到XlGrouped成员,并且不需要IUnknown通过Variant指针查询:一切都简单得多......通常更简单意味着更快。

但是您正在迭代一个对象数组:无论如何,这将比它需要的要慢。

对象想要在 a 中迭代Collection,使用For Each循环。

Dim qc As SettingsColumn
For Each qc In myCollection
    If qc.XlGrouped Then  '<~ note =True is redundant
       '...
    End If
Next

有关更多信息和性能基准,请参阅For vs For Each。底线是,使用循环迭代对象Collection并按For索引检索每个项目,总是比For Each循环慢得多;用于For迭代值数组,For Each迭代对象集合。


推荐阅读