VBA - `With` 语句的目的是什么

VBA - What is the purpose of the `With` statement

我阅读了 Microsoft 的 With-Statement 文档,但仍然不明白 With 语句的目的是什么...


Xpost from Reddit,认为这确实应该在 Stack Overflow 上的某个地方,但找不到任何此类性质的问题。

简介With

想象以下代码(示例 A):

ThisWorkbook.Sheets(1).Range("A1").Font.Color  = rgb(255,0,0)
ThisWorkbook.Sheets(1).Range("A1").Font.Bold   = true
ThisWorkbook.Sheets(1).Range("A1").Font.Italic = true
ThisWorkbook.Sheets(1).Range("A1").Font.Size   = 16

如果我们计算 .s,在这个例子中有 13 个。这意味着对象是通过 属性 访问器访问的,在我们的代码中有 13 次。

当我们改用 With 语句时会发生什么? (示例 B):

With ThisWorkbook.Sheets(1).Range("A1").Font
    .Color  = rgb(255,0,0)
    .Bold   = true
    .Italic = true
    .Size   = 16
End With

如果我们计算新代码中的 . 秒,我们会看到 属性 访问器只被调用了 7 次!所以我们只是通过使用 With 语句将 VBA 必须完成的工作量减半!

这是使用 With 语句的主要好处。

内部运作方式

内部 VBA 正在做这样的事情(示例 C):

Dim temp1 as Object
set temp1 = ThisWorkbook.Sheets(1).Range("A1").Font
temp1.Color  = rgb(255,0,0)
temp1.Bold   = true
temp1.Italic = true
temp1.Size   = 16
set temp1 = nothing 'More specifically temp1 now calls IUnknown::release()

因此您实际上可以使用此代码模仿 With 的行为,但是 With 使用不会污染局部变量范围的“隐藏变量”,因此这可能是首选。


性能注意事项

关于性能,With 语句的使用方式可能会损害性能而不是性能优势。

1。 A是局部变量

Dim A as SomeObject
set A = new SomeObject
With A
    .B = 1
    .C = 2
    .D = 3
End With

在这种情况下,A 是局部变量。如果我们运行通过我们的转换:

Dim A as SomeObject
set A = new SomeObject
Dim temp1 as SomeObject  'Unnecessary call
set temp1 = A            'Unnecessary call
temp1.B = 1
temp1.C = 2
temp1.D = 3
set temp1 = nothing

我们发现我们的代码中可能存在一些性能损害,因为需要定义和设置 temp1。不过,与 属性 访问器相比,性能下降相对可以忽略不计,因此不太可能引起注意。请注意,性能下降在很大程度上可以忽略不计,因为设置对象不会 t运行sfer 整个对象,而是 t运行sfer 指向该对象的指针,这是非常高效的。

PS: 这种性能下降目前只是假设,我将确认这是真的还是编译器优化了性能。

2。 A 是一个成员变量

如果我们有一个class,代码如下:

Public A as object

Sub Test
    With A
        .B = 1
        .C = 2
        .D = 3
    End With
End Sub

在这种情况下,A 是一个 member/property 变量。所以实际上隐藏了一些信息。让我们更正一下:

Public A as object

Sub Test
    With Me.A
        .B = 1
        .C = 2
        .D = 3
    End With
End Sub

啊,现在我们可以看到通过使用 With 我们实际上节省了 3 个成员访问器调用:

Dim Temp1 as object
set Temp1 = Me.A
Temp1.B = 1
Temp1.C = 2
Temp1.D = 3
set temp1 = nothing

Me.A.B = 1
Me.A.C = 2
Me.A.D = 3

最终我要说的是 VBA 可能使用了您看不到的隐藏变量,因此幕后真正发生的事情是非常具体的。在某些情况下,您所做的可能会影响 运行t 使用 With,而在其他情况下则不会。如果有疑问,请使用 With,因为错误的性能优势远远超过其他方面的性能损失。

注意:关于编写代码的速度和层次结构的表示,With 声明有一些小的好处,但是这些主要是我个人的意见,不属于这里。


P-Code 和性能测量

如果有兴趣,这里有一些 PCode 的转储,用于包含和不包含 With 语句

的一组示例

当然,P-Code 只是故事的一半,因为不同的 P-Code 操作将具有不同的速度。这是一个比较。

前 3 列显示了包含本文开头所述的 3 个案例的测试 post。其余测试相对 运行dom 但这是我学到的:

  • with 语句中的局部变量似乎比访问成员变量快得多。
  • 使用 with 会对少量调用造成性能损失。
  • 正如预期的那样,With A.O.O 的表现明显优于 A.O.O.Prop=...
  • 实际上有明显的速度差异。因此,如果您可以尝试将 With 语句保持在您拥有的任何循环之外!

:Excel 2011

Mac 版本 VBA 的所有测试 运行

注意:所有测试 运行 超过 10^8 次迭代 - 这意味着这些性能差异虽然存在,但很小!!