Public 对比 Private/Dim 在 Excel VBA

Public vs Private/Dim in Excel VBA

我可以使用一些帮助来理解在 Excel 2013 VBA.

的模块中使用 Public 与 Dim

首先,我想说的是,我确实发现这个很棒的 post 具有出色的定义(请参阅下面的 link),但没有示例,我可以使用一些示例来说明如何应用 Public 我项目的变量。另外,我对何时需要使用 Option Private Module; 感到有些困惑;我需要在我拥有的每个模块上使用它还是只在包含以下代码的模块上使用它?

Whosebug descriptions difference between Public/Private

我想做的是在标准 Mod 中设置它,这样我就不必通过我的所有用户窗体继续为工作表设置变量,这些用户窗体对它们引用的工作表使用相同的命名约定。

Sub PubVar()
Public wb As Workbook
Public wsSI As Worksheet
Public wsRR As Worksheet
Public wsCalcs As Worksheet
Public wsNarr As Worksheet
Public wsEval As Worksheet
Public wsUW As Worksheet
Public wsLVBA As Worksheet

Set wb = Application.ThisWorkbook
Set wsSI = wb.Sheets("SavedInfo")
Set wsCalcs = wb.Sheets("Calcs")
Set wsNarr = wb.Sheets("Narrative")
Set wsEval = wb.Sheets("EvalCL")
Set wsUW = wb.Sheets("UWCL")
Set wsLVBA = wb.Sheets("ListsForVBA")
End Sub

感谢您的帮助。

如果您正在制作自己的 Excel 加载项(*.XLAM 文件),您实际上只需要 Option Private Module。它允许模块的 Public 变量对加载项自己的项目中的其他模块可见,但防止它们被使用您的加载项的其他工作表 visible/callable。

至于其他的,不清楚你问的是什么。您链接的问题对 Public 与 Dim/Private 有很好的解释。 Private/Dim 变量无法被不同模块、表单中的 VBA 代码或同一 VBA 项目中的 类 看到。如果您希望所有 VBA 代码都能够 see/call,请使用 public。如果你希望它只是来自它自己的模块中的 visible/callable,你可以使用 private/dim。

但是一般来说你想要对你所做的事情保持审慎public,因为它会给你太多的全局名称(混淆),可能会导致问题重名(有问题,可以通过命名标准解决),最重要的是因为它会导致 confusing/obscure 错误和可怕的调试问题(因为任何 public 变量更改都可能导致任何其他可以看到它的代码表现不同)。有些事情比其他事情更糟糕:

Public Subs        OK in a module, but better in a Class
Public Function    Usually fine, especially if its a true function
Public Const       No problem, belongs in modules
Public Variables   Very Bad.  *UNLESS ...*

Public 变量是优秀编码人员担心的。应避免使用它们,除非它们就是我们所说的 "Read-Only Variables"。这些变量您只设置一次,就再也不会更改。只要你遵循这个规则,它们就是有效的常量并且是可以的(虽然只读静态属性会更好,但是VBA在这方面有太多限制)。

最后,如果您想为所有代码中 visible/useable 的所有工作表使用命名变量,但您只需设置一次,这就是 Public 的用途,但是声明 ("Public ") 需要位于“模块级别”,这意味着,在模块中,but 在任何子例程之外或功能。像这样:

Public wb As Workbook
Public wsSI As Worksheet
Public wsRR As Worksheet
Public wsCalcs As Worksheet
Public wsNarr As Worksheet
Public wsEval As Worksheet
Public wsUW As Worksheet
Public wsLVBA As Worksheet

' sets all of the Worksheet variables
Sub PubVar()

    Set wb = Application.ThisWorkbook
    Set wsSI = wb.Sheets("SavedInfo")
    Set wsCalcs = wb.Sheets("Calcs")
    Set wsNarr = wb.Sheets("Narrative")
    Set wsEval = wb.Sheets("EvalCL")
    Set wsUW = wb.Sheets("UWCL")
    Set wsLVBA = wb.Sheets("ListsForVBA")

End Sub

选项私有模块

Option Private Module 应该在任何标准模块中使用,这并不意味着将其 public 成员作为宏(即 Public Sub 过程)或用户公开给 Excel -定义函数(即 Public Function 程序)。

没有这个选项,标准模块的 public 无参数 Sub 过程出现在 Excel 的可用宏列表中,public Function 过程作为可用工作sheet 函数出现在Excel 的单元格“intellisense”中。

请注意,这只是 隐藏了 宏列表中的模块成员:如果您键入“隐藏”过程的确切名称,Excel 仍会 运行它.


昏暗 vs 私人 vs Public

Dim 是用于在过程范围内声明 局部变量 的关键字。关键字也是 合法的 用于声明私有的模块级变量,但是您也可以使用 Private.

当用于声明模块级变量时,Private 使该变量只能从声明它的模块内访问。

当用于声明模块级变量时,Public 使任何有权访问它在其中声明的模块的对象都可以访问该变量 - 在标准模块中,这意味着该变量实际上是 Global.在 class(/document/userform/anything else)模块中,这意味着变量保存 实例状态 并且可以从任何有权访问 实例的对象访问 那 class。 类 有一个 predeclaredId,比如 UserForm classes,都有一个全局可访问的实例:避免在这个默认实例中存储实例状态.


使用Worksheet.CodeName

Set wb = Application.ThisWorkbook
Set wsSI = wb.Sheets("SavedInfo")
Set wsCalcs = wb.Sheets("Calcs")
Set wsNarr = wb.Sheets("Narrative")
Set wsEval = wb.Sheets("EvalCL")
Set wsUW = wb.Sheets("UWCL")
Set wsLVBA = wb.Sheets("ListsForVBA")

ThisWorkbook 是您正在查看的工作簿 - 包含您的 VBA 代码的工作簿。 ThisWorkbook 标识符是全局可访问的,Application.ThisWorkbook 只是指向该对象的指针。

Application.ThisWorkbook 上使用 ThisWorkbook,除非你声明了一个局部变量并将其命名为 ThisWorkbook - 那么该局部变量将是 shadowing 全局标识符;不要那样做。没有任何理由需要用 Application.

限定 ThisWorkbook

现在,如果这些工作sheet中的任何一个在编译时存在于ThisWorkbook中,那么您就不需要这些变量中的任何一个。在 Project Explorer (Ctrl+R) 中找到每个 sheet,然后点击 F4 并为其 (Name) 属性 一个有意义的标识符名称。

因此,如果您将 Sheet1 重命名为 SavedInfoSheet,那么您可以从代码中的任何位置访问 SavedInfoSheet,并且您永远不需要从 Workbook.Sheets(或更好,Workbook.Worksheets)集合。这样做的原因是 VBA 通过您作为 Worksheet 模块的 (Name) 属性 放置的任何标识符的名称自动创建一个全局范围标识符。

如果 sheet 在编译时不存在(即它们是在 运行 时创建的),那么您也不需要这些变量,因为代码创建它们的人应该已经有那个参考:

Set theNewSheet = theBook.Worksheets.Add

然后您可以(并且应该)根据需要将这些工作sheet 对象引用作为参数传递。


没有工作sheet。

What I would like to do is set this up in a Standard Mod so I dont have to continue setting variables for worksheets through all of my UserForms that use the same naming convention for Worksheets they reference

您的表单运行正在展示。触发它们的代码如下所示:

UserForm1.Show

与任何 UI 一样,表单负责收集用户输入,并向用户显示数据。如果您发现自己编写的用户窗体代码隐藏可以访问十几个工作sheets(and/or 更糟,),那么您的窗体就做得很多,很多 比它需要的更复杂,并且您 将一个完整的对象作为过程的容器,通过使其 默认实例 有状态.

This article goes in details about how to fix that. This article 进一步推动概念并允许 viewpresenter 之间的来回通信,并且下载 link 有一个简单的例子来研究(免责声明:我写了这些文章,以及随附的示例代码)。

UserForm 代码做得对,看起来非常简单,负责的逻辑也很少,很无聊。事实上,它不负责 任何 超出 表示 的逻辑 - 所有 UserForm 应该做的,就是响应控制事件,将控制状态传递给某些 model,如果应用程序逻辑需要在窗体关闭之前执行(例如,如果单击命令按钮但窗体应保持打开状态),那么它会触发一个事件,调用代码("presenter") 通过触发需要 运行.

的逻辑来处理它

当对话框正常时,或者当它向 presenter 传递事件时,代码 outside 将执行表单的代码隐藏对于工作:表格永远不需要知道任何关于任何工作的信息sheet.