为什么在使用For Each Next循环之前不必设置对象变量?

时间:2018-11-05 00:26:28

标签: excel vba excel-vba

我正在研究这个简单的宏,但是我不明白为什么在使用ws循环之前不必使用对象引用设置名为For Each ... Next的对象变量。我的逻辑是:

Dim ws As worksheet仅创建存储空间来保存worksheet对象引用。就我而言,这是一个空的对象变量。它还没有保存对象引用。仅指定了其“数据类型”。

因此,当我们在ws行中引用For each ws In ActiveWorkbook.Worksheets时,ws变量在技术上是否为空?我们应该在ws = ActiveSheet上使用一行,以便该变量实际上包含对工作表的对象引用吗?太困惑了。

Sub FormatFormulas()
    Dim ws As worksheet
    On Error Resume Next
    For Each ws In ActiveWorkbook.Worksheets
        With ws.Cells.SpecialCells(xlCellTypeFormulas)
            .NumberFormat = ”#,##0”
            .Interior.ColorIndex = 36
            .Font.Bold = True
        End With
    Next ws
End Sub

3 个答案:

答案 0 :(得分:6)

For Each循环中的运行时行为在VBA语言规范的section 5.4.2.4中有详细说明。

对于数组:

  
      
  • 如果数组的声明类型为 Object ,则 Set 分配给第一个元素   在数组中。否则,为   让我们分配给数组中的第一个元素。
  •   
  • 设置后,将执行。如果存在,则将其执行。
  •   
  • 一旦完成(如果存在),就将分配给数组中的下一个元素(或Set-assigned (如果它是Object的数组)。当且仅当数组中没有其他元素时,的执行立即完成。否则,将再次执行,然后执行(如果存在),然后重复此步骤。
  •   

对于其他可枚举类型(在您的情况下为Workbook.Worksheets),这是运行时行为:

  
      
  • 的数据值必须是对支持实现定义的枚举的外部对象的对象引用   接口。 是让分配的或   设置为分配给<集合>中第一个元素   实施定义的方式。
  •   
  • 设置后,将执行。如果存在,则将其执行。
  •   
  • 一旦完成(如果存在),就将设置为分配给实现中中的下一个元素-确定的方式。如果中没有其他元素,则的执行立即完成。否则,将再次执行,然后执行(如果存在),然后重复此步骤。
  •   

在您的情况下,这基本上可以归结为:编译器会生成一个隐式调用,该调用在首次进入循环以及每次迭代时都会执行以下分配。编译后,将与此类似(实际上比检查Nothing要复杂得多)

Set ws = ActiveWorkbook.Worksheets.[_NewEnum]
Do While ws Is Not Nothing
    With ws.Cells.SpecialCells(xlCellTypeFormulas)
        .NumberFormat = "#,##0"
        .Interior.ColorIndex = 36
        .Font.Bold = True
    End With
    Set ws = ActiveWorkbook.Worksheets.[_NewEnum]
Loop

请注意,这就是为什么在迭代集合时不要更改集合的内容的原因-通过调用[_NewEnum]检索下一个元素。这意味着基础集合返回的项一次被“屈服”,因此在循环内更改集合的内容将影响返回的项,或者可能导致错误({{1}的行为}特定于实现)。

答案 1 :(得分:2)

这里, ws 参考用于一个一个地获取ActiveWorkbook工作表。

For Each ws In ActiveWorkbook.Worksheets

中对以上 ws 的引用
Dim ws As worksheet

不初始化对象,但声明将 ws 变量用作工作表。

答案 2 :(得分:1)

好的,多亏了蒂姆的回答,我才知道了:

我们可以使用Set ws = Worksheets(1)来初始化ws变量,但是对于For Each Next循环则没有必要,因为它会在每次迭代时都设置变量(并且总是基于项目的索引号。