#arrays #excel #vba #class #dictionary
#массивы #excel #vba #класс #словарь
Вопрос:
Что у меня есть:
- Словарь (sData).
- Все элементы в sData являются экземплярами модуля класса (cls).
- Каждый экземпляр модуля класса содержит 2D-массив (cls.arrAtt).
- arrAtt объявлен как общедоступный вариант в модуле класса
- Базовые знания VBA
Что я пытаюсь сделать:
Замените все «истинные» и «ложные» элементы массива на «Да» и «Нет».
For Each key In sData
Set cls = sData(key)
For j = LBound(cls.arrAtt, 2) To UBound(cls.arrAtt, 2)
If cls.arrAtt(1, j) = "true" Then cls.arrAtt(1, j) = "Yes"
If cls.arrAtt(1, j) = "false" Then cls.arrAtt(1, j) = "No"
Next j
Next key
(ЕСЛИ операторы запускаются правильно)
Как вы можете видеть на рисунке, цикл по массиву не изменяет его элементы.
Есть идеи, почему?
Вот как заполняются массивы:
with sh1
For i = 2 To .UsedRange.Rows.count
If sData.Exists(.Cells(i, rCol).Value2) Then
Set cls = sData(.Cells(i, rCol).Value2)
Else
Set cls = New cls_Source_Attributes
sData.Add .Cells(i, rCol).Value2, cls
End If
cls.idRow = i
cls.arrAtt = .Range("" amp; .Cells(i, firstCol).Address amp; ":" amp; .Cells(i, lastCol).Address amp; "")
Next i
End With
Ответ №1:
вы должны добавить «метод» в свой класс, например
Public Sub arrAttChange(i As Long, j As Long, val As Variant)
arrAtt(i, j) = val
End Sub
а затем используйте его в своем коде следующим образом:
For Each key In sData
Set cls = sData(key)
For j = LBound(cls.arrAtt, 2) To UBound(cls.arrAtt, 2)
If cls.arrAtt(1, j) = "true" Then cls.arrAttChange 1, j, "Yes"
If cls.arrAtt(1, j) = "false" Then cls.arrAttChange 1, j, "No"
Next
Next key
Улучшение этого кода с логической точки зрения может быть
For Each key In sData
Set cls = sData(key)
With cls ' <-- reference the object
For j = LBound(.arrAtt, 2) To UBound(.arrAtt, 2)
Select Case .arrAtt(1, j)
Case "true"
.arrAttChange 1, j, "Yes"
Case "false"
.arrAttChange 1, j, "No"
End Select
Next
End With
Next
Другой возможностью является использование «вспомогательного» массива в коде «потребителя» класса, оставляя код класса нетронутым
Dim arrAtt As Variant ' declare a "helper" array
For Each key In sData
Set cls = sData(key)
arrAtt = cls.arrAtt ' initialize the helper array with the values from the class one and change it in the following For - Next loop
For j = LBound(arrAtt, 2) To UBound(arrAtt, 2)
Select Case arrAtt(1, j)
Case "true"
arrAtt(1, j) = "Yes"
Case "false"
arrAtt(1, j) = "No"
End Select
Next
cls.arrAtt = arrAtt ' assign the changed array back to the class array
Next
Комментарии:
1. Извините за мой поздний отзыв. Спасибо за ваш быстрый ответ и советы тоже. Не могли бы вы объяснить мне, почему это работает именно так, а не так, как я пытался? И почему cls.arrAtt=arrAtt работает (последняя строка), а cls.arrAtt(1,j)= «No» не работает? Я думал, что это одно и то же.
2. @HYs, я, по общему признанию, не знаю реальной глубокой причины этого, но я предполагаю, что этот
Public
элементVariant
типа может быть назначен только как «целое», как вы сами это делаетеcls.arrAtt = .Range("" amp; .Cells(i, firstCol).Address amp; ":" amp; .Cells(i, lastCol).Address amp; "")
. Хотя его можно запросить в его «деталях»