4

我的目标是使用名称数组在 VBA 中创建动态变量,代码如下:

Sub mymacro()
Dim names()
names = Array("cat_code()", "dog_code()", "eagle_code()")
For Each c In names
Dim c As Integer
Next
end sub

当然,我的真名数组有数百只动物,所以Dim每一个都做会很无聊。我得到的错误是Compile Error: Duplicate declaration in current scope

我的目标的最佳可行解决方案是什么?

4

3 回答 3

6

您得到的编译错误是由当前范围内的重复声明引起的。

换句话说:这意味着您声明了多个具有相同名称的变量。

Option Explicit在模块之上添加语句需要您声明您使用的每个变量。当您收到此错误时,这非常有用,因为您可以快速扫描代码以查找突出显示行的重复声明Dim <variable_name>

这是一个示例,说明您收到错误的原因:

Option Explicit

Sub Main()

    Dim c As Worksheet
    For Each c In Sheets
        Dim c As Long   ' you are going to get an error in here because
                        ' a variable named: c, is already declared within the sub
                        ' you can't have two variables named: c.
        For c = 1 To ws.Range("A" & Rows.Count).End(xlUp).Row
            ' some code
        Next c
    Next

End Sub

解决您的问题并非易事。如果您更好地解释您想要实现的目标,我们将能够为您的问题提供更好的解决方案。

有一种解决方法可以实现您想要的,但如果您不确定自己实际上在做什么,我不建议您这样做;)。下面的代码将在您当前的 VBA 项目中创建一个新模块。在使用动物名称迭代数组时,它将写入新行,Module2因此在执行后您的模块二将是

在此处输入图像描述

为了使此代码工作,您必须在 VBE 窗口中添加对Microsoft Visual Basic for Applications Extensibility 5.3". You can do that by selectingTools References` 的引用。>>

此外,这需要您Trust Access to VBA Project Object Model. 转到 Excel 设置 >> 信任中心 >> 宏 >> 勾选信任访问 VBA 项目对象模型。

在此处输入图像描述

运行示例代码。

Option Explicit

' this VBA project requires
' 1 - references to Microsoft Visual Basic For Applications Extensibility 5.3
'     add it via Tools > References
'
' 2 - trust access to VBA project object model
'     In spreadsheet view go to Excel(application options) >> Trust Centre >> Macro Settings
'     tick the Trust Access to VBA project object model

Sub mymacro()
    Dim names
    names = Array("cat_code", "dog_code", "eagle_code")
    Dim c As Variant
    AddAModule
    For Each c In names
        ' dynamically create arrays
        WriteToModule CStr(c)
    Next
    CloseModule
End Sub


Private Sub AddAModule()
    Dim VBProj As VBIDE.VBProject
    Dim VBComp As VBIDE.vbComponent
    Dim CodeMod As VBIDE.CodeModule

    Set VBProj = ThisWorkbook.VBProject
    Set VBComp = VBProj.VBComponents.Add(vbext_ct_StdModule)
    Set CodeMod = VBComp.CodeModule

    With CodeMod
        .DeleteLines 1, .CountOfLines
        .InsertLines 1, "Public Sub DynamicallyCreatedArrays()"
        .InsertLines 2, "    ' code for the sub"
    End With
End Sub

Private Sub WriteToModule(arrayName As String)
    With ActiveWorkbook.VBProject.VBComponents("Module2").CodeModule
        .InsertLines .CountOfLines + 2, "    Dim " & arrayName & " as Variant"
    End With
End Sub

Private Sub CloseModule()
    With ActiveWorkbook.VBProject.VBComponents("Module2").CodeModule
        .InsertLines .CountOfLines + 2, "End Sub"
    End With
End Sub
于 2013-09-24T10:47:16.033 回答
6

如果不进入一个可怕的复杂世界,VBA 就无法真正做你想做的事情。

改用 VBACollection对象怎么样?您需要创建一个简单的类来保存数字,因为 VBA 集合使用引用而不是值。

所以我创建了一个类并将其名称设置为“ AnimalCounter”,内容如下:

Public Counter As Integer

然后你的宏变成这样:

Sub mymacro()

Dim coll As New Collection
Dim c As Variant
Dim ac As AnimalCounter

    For Each c In Array("cat", "dog", "eagle")
        Set ac = New AnimalCounter
        coll.Add ac, c
    Next

    Debug.Print coll("cat").Counter ' what's in "cat"?
    coll("dog").Counter = coll("dog").Counter + 1 ' update "dog" by one
    Debug.Print coll("dog").Counter ' "dog" should now be one more

End Sub

如果您想要数组,请将数组放入类中。或者另一个Collection,也许?

于 2013-09-24T10:53:30.373 回答
4

Mike Woodhouse 有一个正确的想法,就是将 aCollection与动物的钥匙一起使用。我添加两个注释:

首先,我建议使用 aDictionary代替。它比 a 快Collection,并且允许显式访问KeysItems集合。使用 a Collection,实际上没有办法获取密钥,因为基本目的是一个有序的项目列表,而不是一个与顺序无关的哈希 a Dictionary

对于该Dictionary类型的早期绑定使用,请添加对 Microsoft Scripting Runtime 的引用。

其次,不要为单个动物使用数组!. 原因是因为 VBA 中的数组使用按值语义(有关更多信息,请参阅VBA 中的集合 - 概述、 VBA 中的值和引用数组分配规则)。简而言之,每次你从包含Collectionor中获取一个数组的实例时Dictionary,你都会得到整个数组的一个新副本。因此,您对该数组的内容所做的任何更改都不会影响Dictionaryor中的实际数组Collection。要解决此问题,请改用 a Collection。这将使用按引用语义并使得附加新项目变得更加容易。

所以这就是你想要做的:

Sub ReadCodes() 
    Dim ws As Worksheet
    Dim strAnimalName  As String
    Dim dctAnimalCodes As New Dictionary
    Dim colAnimalCodes As Collection
    Dim lngAnimalCode  As Long 

    Set ws = Worksheets("Animal Code Data")
    For iRow = 1 To ws.UsedRange.Rows.Count
        strAnimalName = ws.Cells(iRow, 1)
        lngAnimalCode = ws.Cells(iRow, 2)

        ' Easy to check if key exists
        If Not dctAnimalCodes.Exists(strAnimalName) Then
            Set dctAnimalCodes(strAnimalName) = New Collection
        End If

        ' Getting the collection for this animal
        Set colAnimalCodes = dctAnimalCodes(strAnimalName)

        ' Easy appending of new code
        colAnimalCodes.Add lngAnimalCode
    Next 
End Sub 
于 2013-09-24T13:58:22.533 回答