web-dev-qa-db-ja.com

バリアント配列が割り当てられていないかどうかを確認するにはどうすればよいですか?

   Dim Result() As Variant

私の時計ウィンドウでは、これは次のように表示されます

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

以下を確認するにはどうすればよいですか。

   if Result is nothing then

または

   if Result is Not Set then

これは基本的に私が達成しようとしていることですが、最初のものは機能せず、2番目のものは存在しません。

13
jason m

Chip Pearsonは、このようなことをテストするための一連の関数を含む modArraySupport という便利なモジュールを作成しました。あなたの場合、あなたはIsArrayAllocatedを使いたいでしょう。

Public Function IsArrayAllocated(Arr As Variant) As Boolean

この関数は、指定された配列が割り当てられている(空ではない)かどうかを示すTRUEまたはFALSEを返します。配列のTRUEを返します。静的配列、またはRedimステートメントで割り当てられた動的配列です。配列がまだReDimでサイズ設定されていない動的配列であるか、Eraseステートメントで割り当てが解除されている場合はFALSEを返します。この関数は基本的に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)

ウォッチウィンドウでのテスト:これを行う方法はいくつかあります。たとえば、Rに時計を追加し、[時計の種類]で[値が変更されたときに中断]を選択します。

エラー処理を回避するために、私はこれを使用しました。これはずっと前にフォーラムで見られ、それ以来成功裏に使用されています。

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
22
RandomCoder

イミディエイトウィンドウで以下を使用できます。

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

1つ目は、完全を期すためのものです。 Resultはオブジェクトではないため、_Result Is Nothing_はエラーをスローします。 Emptyは、初期化されていないバリアント用です ディメンション化されていない配列を含みます。

(更新)いくつかの追加チェックを行ったところ、1つの例外を除いて、IsEmptyが宣言された配列(Redimされているかどうかに関係なく)でtrueを返すことは決してないことがわかりました。私が見つけた唯一の例外は、配列がパブリックとしてではなくモジュールレベルで宣言されている場合と、イミディエイトウィンドウでチェックした場合のみです。

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çoisCorbettによって投稿されたライブラリ)は、配列のサイズが決定されてから消去されるとfalseを返すことに注意してください。

11
Thomas

(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)であり、これは非常に効率的です。唯一のトレードオフは、ベクターのスペースが不足するたびにストレージが2倍になるため、最悪の場合、ベクターのストレージの50%が無駄になることです。

1
Tmdean

受け入れられた回答の4行目は次のように言うべきだと思います。

ReDim Result(1 To 10)

の代わりに:

ReDim V(1 To 10)

5行目:

R = IsArrayAllocated(Result)  ' returns true

3行目と同じようにFALSEを返します。

R = IsArrayAllocated(Result)  ' returns false

結果は4行目で再ディメンション化されたものではないためです。

4行目では、Vという配列の再ディメンション化が試みられていますが、宣言されていません。

0
Andras Dorko

配列のLBoundを確認してください。エラーが発生した場合は、初期化されていません。

0
Tim Williams