VBA - Возвращение массива из свойства Get - PullRequest
13 голосов
/ 10 апреля 2011

Если массивы возвращаются по ссылке, почему не работает следующее:

'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

Ответы [ 3 ]

25 голосов
/ 31 мая 2013

У вас нет свойства let.Кроме того, свойство get возвращает весь массив, а не только рассматриваемый элемент.Измените тип возврата свойства Get с Double () на обычный Double.Добавить недвижимостьОбратите внимание, что требуется два входа, но только один передается на него.Предполагается, что последняя переменная (в данном случае 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  
12 голосов
/ 10 апреля 2011

В VBA массивы никогда не возвращаются по ссылке, если они не возвращаются через параметр ByRef. Кроме того, всякий раз, когда вы используете = для присвоения массива переменной, вы создаете новую копию массива, даже если вы присваиваете ее аргументу ByRef внутри процедуры, так что вы в значительной степени исключены удачи, пытаясь сделать эту работу.

Некоторые альтернативы ...

  • Используйте VBA.Collection вместо массива.
  • Создайте свой собственный класс, который инкапсулирует массив и предоставляет процедуры для косвенного доступа и манипулирования внутренним массивом.
0 голосов
/ 18 июня 2019

Я хочу предложить другой хороший способ сделать это, используя 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

Превратить это в массив или реализовать его в виде массива просто, но коллекции кажутся мне более полезными, с тем недостатком, что их элементы не проверяются неявно / проверяется тип (время компиляции).
Так что это, например, превратит его в массив (только для чтения) (с недостатком 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 S s answer в статическое, изменяемое свойство модуля с использованием некоторого массива будет следующим:

'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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...