Аргумент об ошибке компиляции Excel VBA Не является обязательным при переборе массива, присоединенного к коллекции классов. - PullRequest
1 голос
/ 30 сентября 2019

Я получаю сообщение об ошибке «Ошибка компиляции: Аргумент не является обязательным» при циклическом просмотре массивов Team / Group, прикрепленных к классу Event, хранящемуся в коллекции.

Выдает ошибку компиляции в строках, поскольку это не такобрабатывая объект как массив:

For ctr = LBound(evt.Team) To UBound(evt.Team)
For ctr = LBound(evt.Group) To UBound(evt.Group)

Но когда я напрямую печатаю его, ссылаясь на индекс, он работает ... как эта строка:

Debug.Print evt.Team(0)
Debug.Print evt.Group(1)

Мое требование простое.

  1. Считать данные из Данные Excel и сохранить каждое событие в коллекции для дальнейшей обработки.
  2. Массивы Team и Group добавляются в класс Event, в котором хранится команда. только сведения и соответствующие им группы (помеченные как «Y»)

Пока все работает нормально, и данные Event Collection хранятся в правильном порядке *1020*.

Проблема возникает, когда я пытаюсь выполнить итерацию коллекции и выполнить цикл по массивам Team и Group.

Код модуля событий

Option Explicit

Dim ws As Excel.Worksheet
Dim colEvents As Collection
Dim hdrRow1, hdrRow2, startRow, startCol, lastRow, lastCol
Dim startTeam, endTeam, startGroup, endGroup
Dim ctr, ctrRow, ctrCol

Sub Main()
    Set ws = ThisWorkbook.Sheets("Events")
    Set colEvents = New Collection

With ws
    lastRow = (.UsedRange.Rows.Count)
    lastCol = (.UsedRange.Columns.Count)
    'Debug.Print "Last Row: " & lastRow & " - " & "Last Column: " & lastCol

    hdrRow1 = 1
    hdrRow2 = 2
    startRow = 3
    startCol = 1
    startTeam = 4
    endTeam = 6
    startGroup = 7
    endGroup = 11

    'Get Groups
    For ctrRow = startRow To lastRow
        Dim oEvent As clsEvent
        Set oEvent = New clsEvent

        'Get No, Name, Type
        oEvent.No = .Cells(ctrRow, startCol)
        oEvent.Name = .Cells(ctrRow, startCol + 1)
        oEvent.EType = .Cells(ctrRow, startCol + 2)

        'Get Team Details
        ctr = 0
        For ctrCol = startTeam To endTeam
            oEvent.Team(ctr) = .Cells(ctrRow, ctrCol).Value
            ctr = ctr + 1
        Next

        'Get Group Details
        ctr = 0
        For ctrCol = startGroup To endGroup
            If (.Cells(ctrRow, ctrCol).Value = "Y") Then
                oEvent.Group(ctr) = .Cells(hdrRow2, ctrCol).Value
                ctr = ctr + 1
            End If
        Next

        colEvents.Add oEvent
    Next
End With

'Check Collection
Dim evt As clsEvent
For Each evt In colEvents
    Debug.Print "No: " & evt.No
    Debug.Print "Name: " & evt.Name
    Debug.Print "Type: " & evt.EType

    'Loop through Team array
    Debug.Print "Team Details: "
    For ctr = LBound(evt.Team) To UBound(evt.Team)
        Debug.Print evt.Team(ctr)
    Next

    'Loop through Group array
    Debug.Print "Group Details"
    For ctr = LBound(evt.Group) To UBound(evt.Group)
        Debug.Print evt.Group(ctr)
    Next
Next
End Sub

Событие модуля класса

Option Explicit

Private pNo As Integer
Private pName As String
Private pEType As String
Private pTeam(2) As Integer
Private pGroup() As String

'Prop No
Public Property Get No() As Integer
    No = pNo
End Property

Public Property Let No(ByVal vNewValue As Integer)
    pNo = vNewValue
End Property

'Prop Events
Public Property Get Name() As String
    Name = pName
End Property

Public Property Let Name(ByVal vNewValue As String)
    pName = vNewValue
End Property

'Prop Event Type
Public Property Get EType() As String
    EType = pEType
End Property

Public Property Let EType(ByVal vNewValue As String)
    pEType = vNewValue
End Property

'Prop Type
Public Property Get Team(ByVal index As Long) As Integer
    Team = pTeam(index)
End Property

Public Property Let Team(ByVal index As Long, ByVal vNewValue As Integer)
    pTeam(index) = vNewValue
End Property
'Prop Group
Public Property Get Group(ByVal index As Long) As String
    Group = pGroup(index)
End Property

Public Property Let Group(ByVal index As Long, ByVal vNewValue As String)
    If (Not pGroup) = -1 Then
        ReDim Preserve pGroup(0)
    End If
    If (index > UBound(pGroup)) Then ReDim Preserve pGroup(index)
    pGroup(index) = vNewValue
End Property

Private Sub Class_Initialize()
    'statements
End Sub

Private Sub Class_Terminate()
    'statements
End Sub

1 Ответ

1 голос
/ 01 октября 2019

Team не является массивом, поэтому VBA не рассматривает его как единое целое.

TeamGroup) являются индексированными свойствами . Они абстрагируют тот факт, что инкапсулированные данные хранятся в массиве. Для вызывающего кода данные также могут быть сохранены в Collection, Dictionary, ArrayList, HashSet .... это вообще не имеет значения: с учетом индекса свойство являетсявозможность извлекать и возвращать элемент.

Как правило, вы предоставляете индексированные свойства для пользовательского класса коллекции - и вы предоставляете такое свойство вместе с другими членами, такими как Count, Add и Clear.

Но это не пользовательский класс коллекции.

Таким образом, решение может состоять в том, чтобы предоставить свойства TeamCount и GroupCount. Обратите внимание, что если вы откроете UBound(pTeam) или UBound(pGroup), это приведет к вытеканию абстракции и может вызвать проблемы, если впоследствии вы решите, что у вас будет Collection для хранения инкапсулированных данных.

Public Property Get TeamCount() As Long
    TeamCount = UBound(pTeam) + 1 '<~ array is zero-based, so count is +1
End Property

Public Property Get GroupCount() As Long
    If UBound(pGroup) >= 0 Then '<~ would be -1 if uninitialized
        GroupCount = UBound(pGroup) + 1
    End If
End Property

Затем вы можете сделать:

For ctr = 0 To evt.TeamCount - 1

Обратите внимание, что это все еще утечка абстракции: нулевая природа инкапсулированного массива кровоточит повсюду.

Лучшая абстракция позволила бы эторабота:

For Each t In evt.Teams

Есть несколько способов добиться этого - вот самый простой (и, вероятно, наименее эффективный):

Public Property Get Teams() As Collection
    Dim result As Collection
    Set result = New Collection
    Dim i As Long
    For i = LBound(pTeams) To UBound(pTeams)
        result.Add pTeams(i)
    Next
    Set Teams = result
End Property
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...