如何正确使用一组VBA类模块?

时间:2017-06-22 14:09:30

标签: excel vba class collections

我想创建一系列机场。

机场有很多参数,但为了简单起见,我们假设在机场舱模块中定义了机场等级:

'Class Airport
 Public name As String ' Stores name of the airport
 Public flights As Long ' Stores number of flights in that airport

然后我的模块非常大,但这是我从Excel文件中读取列并在机场集合中存储值,删除重复列的部分:

Dim airports As Collection
Set airports = New Collection

'Putting airports in collection
                Dim c As Range
                For Each c In wsToCheck.Range("D:D")
                On Error Resume Next
                Dim airport As New Airport
                airport.name = c.Value
                airports.Add airport, c.Value
                On Error GoTo 0
                Next

如果我在中间

  

Debug.Print airport.name

我得到了名字,但是当我做的时候

  

Debug.Print机场(1).name

什么都没打印(但也没有错误)。

之前我正在使用一系列字符串,它正在运行。但是我现在每个机场需要不止一个字符串。

我的代码有什么问题?我正在使用馆藏吗?

2 个答案:

答案 0 :(得分:4)

您的代码有两个问题。

第一个是可能会创建一个包含数百万个项目的Collection,因为您要迭代的范围都是D列(D:D)。这需要受到约束。

第二个问题是您的变量名称airport与您的班级Airport完全相同。这很容易混淆VBA,因此您需要为其中一个选择不同的名称。

这是一个有效的例子:

Option Explicit

Sub test()
    Dim wsToCheck As Worksheet
    Set wsToCheck = ThisWorkbook.Sheets("Sheet1")

    Dim airportNames As Range
    Set airportNames = wsToCheck.Range("D1:D10")

    Dim airports As Collection
    Set airports = New Collection

    'Putting airports in collection
    Dim i As Long
    Dim c As Range
    For Each c In airportNames
        Dim thisAirport As Airport
        'Debug.Print c.Address & "=" & c.Value
        Set thisAirport = New Airport
        thisAirport.name = c.Value
        thisAirport.flights = i
        i = i + 1
        airports.Add thisAirport
    Next

    'now print them out
    For i = 1 To airports.Count
        Debug.Print airports(i).name & ", " & airports(i).flights
    Next i

End Sub

答案 1 :(得分:1)

除了@PeterT提到的问题之外,代码中最大的问题是创建新Airport对象的方式。我应该更好地说Airport对象,因为实际上没有对象而只有一个对象。

这是由宣布机场变量的方式引起的:Dim airport As New Airport。在VBA-DocumentationDim语句中,我们可以找到为什么在这里只创建一个对象的原因:

  

新关键字可以隐式创建对象。如果你使用新的   在声明对象变量时,对象的新实例是   在第一次引用时创建,因此您不必使用Set   用于分配对象引用的语句。

因此Dim New确保在第一次使用变量airport时创建新实例。但就是这样。没有创建其他实例,只是第一个。在每个循环中,只更改此一个实例并将其添加到集合中。因此,您的集合包含对同一机场对象的引用。

但你需要所有机场对象,而不仅仅是那个。因此New必须与Set一起使用。文档说:

  

当New与Set一起使用时,它会创建一个新类

考虑以下代码(范围D1:D3包含值AAAA,BBBB,CCCC)

Dim airports As Collection
Set airports = New Collection
Dim c As Range

For Each c In Worksheets(1).Range("D1:D3")
    Dim Airport As New Airport
    Airport.name = c.Value
    airports.Add Airport
Next

Dim airports2 As Collection
Set airports2 = New Collection
Dim airport2 As Airport
For Each c In Worksheets(1).Range("D1:D3")
    Set airport2 = New Airport
    airport2.name = c.Value
    airports2.Add airport2
Next

Debug.Print "Airports:"
For Each airport2 In airports
    Debug.Print airport2.name
Next

Debug.Print vbNewLine

Debug.Print "Airports2:"
For Each airport2 In airports2
    Debug.Print airport2.name
Next
  

输出

Airports:
CCCC
CCCC
CCCC


Airports2:
AAAA
BBBB
CCCC

This question也存在同样的问题。