Как проверить, не является ли вариантный массив нераспределенным?

   Dim Result() As Variant

В окне просмотра это выглядит как

Expression | Value | Type
Result     |       | Variant/Variant()

Как проверить следующее:

   if Result is nothing then

или

   if Result is Not Set then

Это в основном то, что я пытаюсь выполнить, но первый не работает, а второй не существует.

Ответ 1

Чип Пирсон создал полезный модуль с именем modArraySupport, который содержит набор функций для проверки подобных вещей. В вашем случае вы хотели бы использовать IsArrayAllocated.

Public Function IsArrayAllocated(Arr As Variant) As Boolean

Эта функция возвращает TRUE или FALSE, указывающие, выделен ли указанный массив (не пустой). Возвращает ИСТИНА массив - это статический массив или динамический объект, который был выделен с помощью оператора Redim. Возвращает FALSE, если массив является динамическим массивом, который еще не был измерен с ReDim или был освобожден с помощью оператора Erase. Эта функция в основном противоположна ArrayIsEmpty. Например,

Dim Result() As Variant
Dim R As Boolean
R = IsArrayAllocated(Result)  ' returns false
ReDim V(1 To 10)
R = IsArrayAllocated(Result)  ' returns true

Методика, в основном, используется для проверки границ массива (как это было предложено @Tim Williams), НО с дополнительным уловком.

Чтобы проверить в вашем ближайшем окне:

?IsArrayAllocated(Result)

Тестирование в окне Watch: могут быть способы сделать это; например, добавьте часы на R и в разделе "Тип часов" выберите "Перерыв при изменении значения".

Ответ 2

Чтобы избежать обработки ошибок, я использовал это, увиденное на форуме давным-давно и успешно используя с тех пор:

If (Not Not Result) <> 0 Then 'Means it is allocated

или, альтернативно,

If (Not Not Result) = 0 Then 'Means it is not allocated

Я использовал это главным образом для расширения размера массива из unset массива таким образом

'Declare array
Dim arrIndex() As Variant        

'Extend array
If (Not Not Result) = 0 Then
    ReDim Preserve Result(0 To 0)
Else
    ReDim Preserve Result(0 To UBound(Result) + 1)
End If

Ответ 3

В ближайшем окне вы можете использовать следующее:

?Result Is Nothing
?IsNull( Result )
?IsEmpty( Result )
?IsMissing( Result )

Первое просто для полноты. Поскольку Result не является объектом, Result Is Nothing выдаст ошибку. Empty для вариантов, которые не были инициализированы , включая массивы, которые не были определены..

(Update) При выполнении дополнительной проверки я обнаружил, что IsEmpty никогда не вернет true в объявленном массиве (будь то Redim'd или нет) только с одним исключением. Единственное исключение, которое я нашел, - это когда массив объявлен на уровне модуля, а не как Public, а затем только тогда, когда вы проверяете его в непосредственном окне.

Missing, если для дополнительных значений передано функции или под. Пока вы не можете объявить Optional Foo() As Variant, вы можете иметь что-то вроде ParamArray Foo() As Variant, в этом случае, если ничего не передано, IsMissing вернет true.

Таким образом, единственный способ определить, инициализирован ли массив, - написать процедуру, которая проверяет:

Public Function IsDimensioned(vValue As Variant) As Boolean
    On Error Resume Next
    If Not IsArray(vValue) Then Exit Function
    Dim i As Integer
    i = UBound(Bar)
    IsDimensioned = Err.Number = 0
End Function

Btw, следует отметить, что эта подпрограмма (или библиотека, выложенная Жаном-Франсуа Корбеттом) вернет false, если массив задан и затем удален.

Ответ 4

Проверьте LBound массива. Если вы получите сообщение об ошибке, то оно не инициализируется.

Ответ 5

Я рекомендую немного другой подход, потому что я думаю, что использование артефактов языка, таких как (Not Array) = -1 для проверки инициализации, трудно читать и вызывает головные боли обслуживания.

Если вам нужно проверить распределение массива, скорее всего, это связано с тем, что вы пытаетесь создать свой собственный "векторный" тип: массив, который растет во время выполнения для размещения данных по мере их добавления. VBA упрощает реализацию векторного типа, если вы воспользуетесь системой типов.

Type Vector
    VectorData() As Variant
    VectorCount As Long
End Type

Dim MyData As Vector

Sub AddData(NewData As Variant)
    With MyData
        ' If .VectorData hasn't been allocated yet, allocate it with an
        ' initial size of 16 elements.
        If .VectorCount = 0 Then ReDim .VectorData(1 To 16)

        .VectorCount = .VectorCount + 1

        ' If there is not enough storage for the new element, double the
        ' storage of the vector.
        If .VectorCount > UBound(.VectorData) Then
            ReDim Preserve .VectorData(1 To UBound(.VectorData) * 2)
        End If

        .VectorData(.VectorCount) = NewData
    End With
End Sub

' Example of looping through the vector:
For I = 1 To MyData.VectorCount
    ' Process MyData.VectorData(I)
Next

Обратите внимание, что нет необходимости проверять распределение массива в этом коде, потому что мы можем просто проверить переменную VectorCount. Если это 0, мы знаем, что ничего еще не добавлено в вектор, и поэтому массив нераспределен.

Этот код не только прост и понятен, но и имеет все преимущества производительности массива, а амортизированная стоимость добавления элементов на самом деле O (1), что очень эффективно. Единственным компромиссом является то, что из-за того, что хранилище удваивается каждый раз, когда вектор заканчивается из пространства, в худшем случае 50% векторного хранилища теряется.

Ответ 6

Я думаю, что в строке 4 принятого ответа должно быть сказано:

ReDim Result(1 To 10)

Вместо:

ReDim V(1 To 10)

Я верю в строку 5:

R = IsArrayAllocated(Result)  ' returns true

вернет FALSE, как в строке 3:

R = IsArrayAllocated(Result)  ' returns false

потому что Result - это не то, что пересмотрено в строке 4.

В строке 4 пытается изменить размерность массива V, но он даже не объявлен.