【问题标题】:How to check whether a variant array is unallocated?如何检查变量数组是否未分配?
【发布时间】:2011-07-25 17:42:08
【问题描述】:
   Dim Result() As Variant

在我的监视窗口中,这显示为

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

如何检查以下内容:

   if Result is nothing then

   if Result is Not Set then

这基本上是我想要完成的,但是第一个不起作用,第二个也不存在。

【问题讨论】:

    标签: vba variant


    【解决方案1】:

    为了避免错误处理,我使用了这个,很久以前在一个论坛上看到并从那时起成功使用:

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

    或者

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

    我主要用这种方式从未设置的数组中扩展数组大小

    '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
    

    【讨论】:

    • 非常感谢!这个真的很棒,但是“Not Not”如何防止没有它们的类型不匹配?
    • 你指的是forumpost吗?
    • 这太棒了!但是为什么Not Not Result &lt;&gt; 0 会导致类型不匹配?不应该一样吗?
    • 比接受的答案中的 20 行函数简单得多。
    • 并且论坛帖子说 - “对于任何感兴趣的人,Not Arrayname 揭示(或不)指向 VB 用于定义数组的 SafeArray 结构的指针的反转。Not Not Arrayname 返回实际指针或 0如果数组未初始化。"
    【解决方案2】:

    您可以在即时窗口中使用以下内容:

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

    第一个只是为了完整性。由于 Result 不是对象,Result Is Nothing 会抛出错误。 Empty 用于未初始化的变体包括未标注尺寸的数组。

    (更新)在做一些额外的检查时,我发现 IsEmpty 永远不会在声明的数组上返回 true(无论是否 Redim'd),只有一个例外。我发现的唯一例外是当数组在模块级别声明而不是公共时,只有当您在即时窗口中检查它时。

    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
    

    顺便说一句,应该注意的是,如果数组被确定尺寸然后被擦除,这个例程(或 Jean-François Corbett 发布的库)将返回 false。

    【讨论】:

    • Result 是一个数组。 IsNull()IsEmpty()IsMissing() 的返回值紧跟在维度之后是 FALSEResult Is Nothing 会引发错误。如果Result 不是数组,我想你的答案会很好。
    • @OP2506 - 因为 Result 不是对象,所以 Is Nothing 会抛出错误。但是,在数组上调用 Redim 之前,IsEmpty 将返回 true。如果没有向声明为 Optional Foo As Variant 的参数传递任何内容,IsMissing 将返回 true,该参数可以包含一个数组。
    • @Jean-François Corbett - 实际上,我做到了。但是,我注意到行为有所不同。如果您在模块级别声明 Result(),然后在即时窗口中运行 IsEmpty( Result ),它将返回 true。但是,如果你把它放在一个例程中并执行 Debug.Print,它会返回 false。
    • @OP2506 是对的。当有人这样挑战你时,在放弃挑战之前做一些测试是没有坏处的!这是我的即时窗口中的复制粘贴:?IsNull( Result ) False ?IsEmpty( Result ) False ?IsMissing( Result ) False
    【解决方案3】:

    Chip Pearson 制作了一个名为modArraySupport 的有用模块,其中包含一堆函数来测试此类事情。在您的情况下,您可能希望使用IsArrayAllocated

    Public Function IsArrayAllocated(Arr As Variant) As Boolean
    

    此函数返回 TRUE 或 FALSE,指示指定的数组是否已分配(非空)。返回 TRUE array 是一个静态数组或一个已使用 Redim 语句分配的动态数组。如果数组是动态数组,则返回 FALSE 尚未使用 ReDim 调整大小或已使用 Erase 语句解除分配。这个功能基本上是相反的 数组是空的。例如,

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

    所使用的技术基本上是为了测试数组边界(正如@Tim Williams 所建议的那样),但有一个额外的陷阱。

    在您的即时窗口中进行测试:

    ?IsArrayAllocated(Result)
    

    在 Watch 窗口中测试:有多种方法可以做到这一点;例如,在R 上添加一个手表,然后在“手表类型”下选择“值更改时中断”。

    【讨论】:

      【解决方案4】:

      我推荐一种稍微不同的方法,因为我认为使用像 (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% 的存储空间被浪费了。

      【讨论】:

        【解决方案5】:

        检查数组的LBound。如果你得到一个错误,那么它是未初始化的。

        【讨论】:

        • 没有帮助,除非您发布如何检查错误的 VBA 代码
        猜你喜欢
        • 2016-03-28
        • 2013-01-31
        • 2011-02-26
        • 1970-01-01
        • 2022-11-17
        • 2018-01-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多