如何阻止Excel VBA重命名不相关模块和方法中的变量和参数



我注意到Excel VBA令人难以置信的破坏行为。当我向类添加一个新属性时,它会无声地自动重命名不相关模块中的变量和函数参数。在Office Professional Plus 2016和Windows 10上观察。

举个具体的例子,我有一个模块和一个类。模块如下:

Private Function MyRequests() As Collection
Dim requests As Collection
Set requests = New Collection
Dim row As Integer
row = 3
Dim oRequest As New MyRequest
oRequest.Name = "SomeName"
requests.Add oRequest
MyRequests = requests
End Function

MyRequest如下所示:

Private sName As String
Property Let Name(sValue As String)
sName = sValue
End Property

现在,令人难以置信的部分来了。我将新属性添加到MyRequest类:

Private iRow As Integer
Property Let Row(iValue As Integer)
iRow = iValue
End Property

我保存代码,转到模块及其私人功能,现在看起来像这样:

Private Function MyRequests() As Collection
Dim requests As Collection
Set requests = New Collection
Dim Row As Integer
Row = 3
Dim oRequest As New MyRequest
oRequest.Name = "SomeName"
requests.Add oRequest
MyRequests = requests
End Function

请注意,row变成了Row!这种无声的自动重命名也发生在工作表中的VBA代码中。。。基本上所有地方,Excel都将row重命名为Row

所以,我的问题是,我能做些什么来阻止这种疯狂的行为?

用与关键字相同的名称命名变量不是一个好的做法

如果关键字[的范围内使用,并且具有[的变量<strike]具有相同的名称,则该关键字必须使用适当的VBA对象模型限定,否则该变量优先,编译器将该关键字解释为该变量。这导致代码更容易出错,而且维护起来明显更困难。>


"所以,我的问题是,我能做些什么来阻止这种疯狂的行为">

解决方案是不声明与VBA关键字同名的变量

相同范围的所有变量共享相同的大小写。在声明处更改大小写会更改范围内变量的每个实例。关键字略有不同,因为它们是全局的,但它们的大小写可以通过本地声明进行更改

因此,在任何范围内,声明一个与关键字同名的变量都会导致该词的每个实例在整个项目范围内共享相同的大小写,并且在删除声明后,更改仍然存在。


关键字由对象模型定义。

VBA对象模型中关键字列表的链接(注释中的链接指向.NET):
https://learn.microsoft.com/en-us/office/vba/language/reference/keywords-visual-basic-for-applications

链接到Excel对象模型(我不知道在哪里可以找到精简列表,但如果它是对象、属性或方法,那么它就是关键字):https://learn.microsoft.com/en-us/office/vba/api/overview/excel/object-model


避开每个关键词可能很有挑战性,甚至是不可能的,这就是范围发挥作用的地方,我可以提供一些易于遵循的建议

当你发现自己命名一个有潜在冲突的变量(如行、列、工作表)时,

  • 在所有情况下,最好使用更具描述性的名称(indexRow、lastRow、rowCounter)

  • 如果找不到合适的名称,请按F2键打开对象模型查看器并搜索该名称。希望搜索不会出现任何结果,并且您可以安全地使用该名称。但如果没有,请查找冲突发生的位置

    • 如果您正在创建Excel项目,并且在Outlook对象中发现冲突,则不会出现问题。您甚至可以考虑从您的项目中删除对Outlook对象的引用

    • 如果它是一个属性名称(如Color)或一个方法(如Resize),那么您可以小心使用(在某些情况下,这实际上是理想的,比如为自定义类分配属性和方法时)

    • 如果它是一个对象(比如工作簿),那么你就不应该使用它。风险太大了。

[我突破了范围的要点——我似乎与我的命名约定相当一致,并且没有意识到变量的大小写发生了变化,而与范围无关。如果不是迈克尔的回答,我永远不会知道

这个问题并没有出现,因为您使用的变量名与内置属性匹配。它的出现只是因为你对同一个变量使用了两种不同的大小写拼写。如果在一个模块中使用iRow,在另一个模块使用irow,仍然会出现相同的问题。

你无法阻止这种行为。VBA IDE会自动更改子例程、函数、变量和属性的名称,以匹配上次编辑的声明语句的大小写。然后,它还会记住在代码中任何地方输入/编辑的所有未来实例所使用的案例。

在进行重命名时,IDE不会区分局部变量和全局变量,也不会区分不同类的属性。如果您在任何地方更改案例,它将被更新并在任何地方使用。

这实际上有助于防止意外的代码错误。VBA不区分大小写,使用不同的大小写不会创建不同的变量。尝试根据案例管理不同的变量,即使是在不同的模块中,也是不好的做法。

如果它们是本地的并且不同,没有混淆的风险,那么你也可以使用相同的大小写拼写。为什么一个模块中有一个命名约定,而另一个模块有不同的命名约定?

然而,如果您需要区分不同模块中的变量,那么无论如何都应该使用不同的字符拼写,这样做不会出现问题。

这种行为还可以帮助您确保在键入时正确输入代码,尤其是如果您用至少一个大写字母声明所有变量、子例程等。然后,您可以只使用小写来编辑所有代码,这减少了工作量,然后所有拼写正确的代码都将自动转换为声明的大小写。如果您用小写键入变量,但它不会自动更改大小写,那么您会立即知道您键入了错误的变量,而不是只有在尝试编译/运行时才发现错误。

请注意,之所以,是因为使用内置属性作为变量和子例程的名称,原因是自动更改大小写在这里也同样适用。因此,如果您将一个变量定义为VALue,那么无论在哪里使用,它都会重命名.Value属性。

如果随后将子例程定义为value,它将重命名现有的VALue变量和.Value属性。

如果您遵循良好的命名约定,并且不在任何地方重复使用名称,那么您就不会有这个问题。

最新更新