VBA - Возвращаемый массив из свойства Get
Если массивы возвращаются по ссылке, почему не работает следующее:
'Class1 class module
Private v() As Double
Public Property Get Vec() As Double()
Vec = v()
End Property
Private Sub Class_Initialize()
ReDim v(0 To 3)
End Sub
' end class module
Sub Test1()
Dim c As Class1
Set c = New Class1
Debug.Print c.Vec()(1) ' prints 0 as expected
c.Vec()(1) = 5.6
Debug.Print c.Vec()(1) ' still prints 0
End Sub
Ответы
Ответ 1
В VBA массивы никогда не возвращаются по ссылке, если они не возвращаются через параметр ByRef
. Кроме того, всякий раз, когда вы используете =
для назначения массива переменной, вы сделали новую копию массива, даже если вы назначили его аргументу ByRef внутри процедуры, так что вы в значительной степени удачи, пытаясь сделать эту работу.
Некоторые альтернативы...
- Используйте VBA.Collection вместо массива.
- Создайте свой собственный класс, который инкапсулирует массив и предоставляет процедуры для косвенного доступа и управления внутренним массивом.
Ответ 2
У вас нет свойства let. Кроме того, свойство get возвращает весь массив, а не только этот элемент. Измените возвращаемый тип свойства Get из Double() на простое двойное. Добавить свойство Let. Обратите внимание, что он принимает два входа, но ему передается только одно. Предполагается, что последняя переменная (MyValue, в данном случае) получает значение от значения после знака =. Поместите точку разрыва где-нибудь в начале теста Test1() и посмотрите, как это значение влияет на окно Locals. Сравните переменные, созданные исходным кодом по сравнению с моим кодом:
'Class1 class module
Private v() As Double
Public Property Get Vec(index As Long) As Double
Vec = v(index)
End Property
Public Property Let Vec(index As Long, MyValue As Double)
v(index) = MyValue
End Property
Private Sub Class_Initialize()
ReDim v(0 To 3)
End Sub
' end class module
'Begin module
Sub Test1()
Dim c As Class1
Set c = New Class1
Debug.Print c.Vec(1) ' prints 0 as expected
c.Vec(1) = 5.6
Debug.Print c.Vec(1) ' prints 5.6
End Sub
'End module
Ответ 3
Я хочу предложить другой хороший способ сделать это, используя Collection
и static Property
без необходимости использовать класс:
представьте, что вы хотите иметь перечисление xlCVError
в виде массива (или коллекции), например, чтобы проходить по нему в случае ошибок и обрабатывать его на основе фактической ошибки.
Следующее инициализируется один раз при доступе:
'from https://stackoverflow.com/a/56646199/1915920
Static Property Get XlCVErrorColl() As Collection
Dim c As Collection 'will be already initalized after 1st access
'because of "Static Property" above!
Set XlCVErrorColl = c
If Not c Is Nothing Then Exit Property
'initialize once:
Set c = New Collection
c.Add XlCVError.xlErrDiv0
c.Add XlCVError.xlErrNA
c.Add XlCVError.xlErrName
c.Add XlCVError.xlErrNull
c.Add XlCVError.xlErrNum
c.Add XlCVError.xlErrRef
c.Add XlCVError.xlErrValue
Set XlCVErrorColl = c
End Property
Превратить это в массив или реализовать его в виде массива просто, но коллекции кажутся мне более полезными, с недостатком в том, что их элементы не являются неявно типизированными /(compile-time-) тип проверен.
Так что это, например, превратит его в массив (только для чтения) (с недостатком in-mem-copy-недостатка, упомянутым в других ответах/комментариях):
'from https://stackoverflow.com/a/56646199/1915920
Static Property Get XlCVErrorArr() As XlCVError()
Dim a() As XlCVError
XlCVErrorArr = a
If UBound( a ) > 0 Then Exit Property
'initialize once:
Dim c As Collection: Set c = XlCVErrorColl
ReDim a(c.Count)
Dim i As Integer: For i = 1 To c.Count
a(i) = c(i)
Next i
XlCVErrorArr = a
End Function
Таким образом, преобразуя пример из ответа Clayton Ss в статическое, модифицируемое свойство модуля, используя некоторый массив, это будет:
'module (no class required)
'from https://stackoverflow.com/a/56646199/1915920
Private v() As Double
Static Property Get Vec(index As Long) As Double
If UBound(v) < 3 Then 'initialize once:
ReDim v(0 To 3) 'one could initialize it with anyting after here too
end if
Vec = v(index)
End Property
Public Property Let Vec(index As Long, MyValue As Double)
v(index) = MyValue
End Property
Ответ 4
Vec (индекс As Long, MyValue As Double)
Что здесь делает ключевое слово index?
Пожалуйста, направьте меня на веб-страницу, где я могу узнать об индексе, связанном с этим массивом.