#arrays #excel #vba
#vba #класс #excel #объект
Вопрос:
У меня возникла проблема в VBA, когда каждый элемент в массиве заменяется каждый раз, когда я добавляю что-то в этот массив.
Я пытаюсь просмотреть строки в заданном диапазоне и преобразовать каждую строку этого класса в пользовательский класс (с именем ‘CustomRow’ в приведенном ниже примере). существует также класс manager (называемый ‘CustomRow_Manager’ ниже), который содержит массив строк и имеет функцию для добавления новых строк.
Когда добавляется первая строка, она работает нормально: https://drive.google.com/file/d/0B6b_N7sDgjmvTmx4NDN3cmtYeGs/view?usp=sharing
однако, когда он переходит ко второй строке, он заменяет содержимое первой строки, а также добавляет вторую запись: https://drive.google.com/file/d/0B6b_N7sDgjmvNXNLM3FCNUR0VHc/view?usp=sharing
Есть идеи о том, как это можно решить?
Я создал немного кода, который показывает проблему, посмотрите переменную ‘rowArray’ в классе ‘CustomRow_Manager’
Файл макроса
https://drive.google.com/file/d/0B6b_N7sDgjmvUXYwNG5YdkoySHc/view?usp=sharing
в противном случае код приведен ниже:
Данные
A B C
1 X1 X2 X3
2 xx11 xx12 xx13
3 xx21 xx22 xx23
4 xx31 xx32 xx33
Модуль «Module1»
Public Sub Start()
Dim cusRng As Range, row As Range
Set cusRng = Range("A1:C4")
Dim manager As New CustomRow_Manager
Dim index As Integer
index = 0
For Each row In cusRng.Rows
Dim cusR As New CustomRow
Call cusR.SetData(row, index)
Call manager.AddRow(cusR)
index = index 1
Next row
End Sub
Модуль класса «CustomRow»
Dim iOne As String
Dim itwo As String
Dim ithree As String
Dim irowNum As Integer
Public Property Get One() As String
One = iOne
End Property
Public Property Let One(Value As String)
iOne = Value
End Property
Public Property Get Two() As String
Two = itwo
End Property
Public Property Let Two(Value As String)
itwo = Value
End Property
Public Property Get Three() As String
Three = ithree
End Property
Public Property Let Three(Value As String)
ithree = Value
End Property
Public Property Get RowNum() As Integer
RowNum = irowNum
End Property
Public Property Let RowNum(Value As Integer)
irowNum = Value
End Property
Public Function SetData(row As Range, i As Integer)
One = row.Cells(1, 1).Text
Two = row.Cells(1, 2).Text
Three = row.Cells(1, 3).Text
RowNum = i
End Function
Модуль класса «CustomRow_Manager»
Dim rowArray(4) As New CustomRow
Dim totalRow As Integer
Public Function AddRow(r As CustomRow)
Set rowArray(totalRow) = r
If totalRow > 1 Then
MsgBox rowArray(totalRow).One amp; rowArray(totalRow - 1).One
End If
totalRow = totalRow 1
End Function
Комментарии:
1. Прочитайте, например, эту статью о
auto-instancing variable
. В общем, вам следует избегать автоматического создания экземпляров переменных. HTH
Ответ №1:
Ваша проблема заключается в использовании
Dim cusR As New CustomRow
внутри For
цикла. Эта строка фактически выполняется только один раз (обратите внимание, что когда вы выполняете один шаг F8 по коду, он не останавливается на этой строке)
Каждая итерация For
цикла использует один и тот же экземпляр cusR. Поэтому все экземпляры manager
, добавленные в класс, указывают на одно и то же cusR
Замените это
For Each row In cusRng.Rows
Dim cusR As New CustomRow
с помощью этого
Dim cusR As CustomRow
For Each row In cusRng.Rows
Set cusR = New CustomRow
Это явно создает экземпляр нового экземпляра класса
Комментарии:
1. Это сделало свое дело! я даже не думал об этом, поскольку обычно я пишу в .NET, где вы могли бы явно создавать новые экземпляры в цикле.
2. Я чувствую, что это конкретное поведение недостаточно хорошо документировано. Существует разница между
Dim v As New ClassObject
ИDim v As ClassObject Set v = New ClassObject
, однако это единственное место, где я нашел это задокументированным.