arrays für - Wie stelle ich fest, ob ein Array in VB6 initialisiert wird?




länge meta (17)

Wenn Sie das Array initialisieren, setzen Sie eine ganze Zahl oder einen booleschen Wert mit einem Flag = 1. und fragen Sie dieses Flag bei Bedarf ab.

Das Übergeben eines nicht dimensionierten Arrays an die Ubound-Funktion des VB6 führt zu einem Fehler, daher möchte ich prüfen, ob es bereits dimensioniert wurde, bevor ich versuche, seine obere Grenze zu prüfen. Wie mache ich das?


Das hat für mich geklappt, irgendeinen Fehler dabei?

If IsEmpty(a) Then
    Exit Function
End If

MSDN


Der einfachste Weg, dies zu umgehen, besteht darin, sicherzustellen, dass das Array im Voraus initialisiert wird, bevor Sie nach dem Ubound suchen müssen. Ich brauchte ein Array, das im Bereich (Allgemein) des Formularcodes deklariert wurde. dh

Dim arySomeArray() As sometype

Dann in der Form laden Routine Redim das Array:

Private Sub Form_Load()

ReDim arySomeArray(1) As sometype 'insure that the array is initialized

End Sub 

Dadurch kann das Array zu einem späteren Zeitpunkt im Programm neu definiert werden. Wenn Sie herausfinden, wie groß das Array sein muss, um es neu zu definieren.

ReDim arySomeArray(i) As sometype 'i is the size needed to hold the new data

Beide Methoden von GSerg und Raven sind nicht dokumentierte Hacks, aber da Visual Basic 6 nicht mehr entwickelt wird, ist das kein Problem. Das Beispiel von Raven funktioniert jedoch nicht auf allen Rechnern. Du musst so testen.

If (Nicht someArray) = -1 Then

Auf einigen Maschinen gibt es eine Null auf eine andere große negative Zahl zurück.


Ich habe das gefunden:

Dim someArray() As Integer

If ((Not someArray) = -1) Then
  Debug.Print "this array is NOT initialized"
End If

Edit : RS Conley hat in seiner answer darauf hingewiesen, dass (Not someArray) manchmal 0 zurückgibt, also muss man ((Not someArray) = -1) verwenden.


Es gibt zwei leicht unterschiedliche Szenarien zum Testen:

  1. Das Array wird initialisiert (effektiv ist es kein Nullzeiger)
  2. Das Array ist initialisiert und hat mindestens ein Element

Fall 2 ist für Fälle wie Split(vbNullString, ",") erforderlich Split(vbNullString, ",") die ein String Array mit LBound=0 und UBound=-1 . Hier sind die einfachsten Codeschnipsel, die ich für jeden Test erstellen kann:

Public Function IsInitialised(arr() As String) As Boolean
  On Error Resume Next
  IsInitialised = UBound(arr) <> 0.5
End Function

Public Function IsInitialisedAndHasElements(arr() As String) As Boolean
  On Error Resume Next
  IsInitialisedAndHasElements = UBound(arr) >= LBound(arr)
End Function

Wenn das Array ein String-Array ist, können Sie die Join () -Methode als Test verwenden:

Private Sub Test()

    Dim ArrayToTest() As String

    MsgBox StringArrayCheck(ArrayToTest)     ' returns "false"

    ReDim ArrayToTest(1 To 10)

    MsgBox StringArrayCheck(ArrayToTest)     ' returns "true"

    ReDim ArrayToTest(0 To 0)

    MsgBox StringArrayCheck(ArrayToTest)     ' returns "false"

End Sub


Function StringArrayCheck(o As Variant) As Boolean

    Dim x As String

    x = Join(o)

    StringArrayCheck = (Len(x) <> 0)

End Function

Dies ist eine Modifikation der answer des Raben. Ohne APIs zu verwenden.

Public Function IsArrayInitalized(ByRef arr() As String) As Boolean
'Return True if array is initalized
On Error GoTo errHandler 'Raise error if directory doesnot exist

  Dim temp As Long
  temp = UBound(arr)

  'Reach this point only if arr is initalized i.e. no error occured
  If temp > -1 Then IsArrayInitalized = True 'UBound is greater then -1

Exit Function
errHandler:
  'if an error occurs, this function returns False. i.e. array not initialized
End Function

Dieser sollte auch bei Split-Funktion funktionieren. Einschränkung ist, dass Sie den Typ des Arrays definieren müssen (String in diesem Beispiel).


Hier ist, was ich gemacht habe. Dies ist ähnlich der answer von GSerg, verwendet aber die besser dokumentierte CopyMemory-API-Funktion und ist vollständig eigenständig (Sie können das Array anstelle von ArrPtr (Array) einfach an diese Funktion übergeben). Es verwendet die VarPtr-Funktion, gegen die Microsoft support.microsoft.com/kb/199824 , aber dies ist eine XP-App, und es funktioniert, also bin ich nicht besorgt.

Ja, ich weiß, dass diese Funktion alles akzeptiert, was Sie werfen, aber ich überlasse die Fehlerüberprüfung als Übung für den Leser.

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
  (pDst As Any, pSrc As Any, ByVal ByteLen As Long)

Public Function ArrayIsInitialized(arr) As Boolean

  Dim memVal As Long

  CopyMemory memVal, ByVal VarPtr(arr) + 8, ByVal 4 'get pointer to array
  CopyMemory memVal, ByVal memVal, ByVal 4  'see if it points to an address...  
  ArrayIsInitialized = (memVal <> 0)        '...if it does, array is intialized

End Function

If ChkArray(MyArray)=True then
   ....
End If

Public Function ChkArray(ByRef b) As Boolean
    On Error goto 1
    If UBound(b) > 0 Then ChkArray = True
End Function

Dim someArray() as Integer    

If someArray Is Nothing Then
    Debug.print "this array is not initialised"
End If

Ich benutze das:

Public Declare Function GetMem4 Lib "msvbvm60" (ByVal pSrc As Long, ByVal pDst As Long) As Long
Public Declare Function ArrPtr Lib "msvbvm60" Alias "VarPtr" (arr() As Any) As Long

Public Function StrArrPtr(arr() As String, Optional ByVal IgnoreMe As Long = 0) As Long
  GetMem4 VarPtr(IgnoreMe) - 4, VarPtr(StrArrPtr)
End Function

Public Function UDTArrPtr(ByRef arr As Variant) As Long
  If VarType(arr) Or vbArray Then
    GetMem4 VarPtr(arr) + 8, VarPtr(UDTArrPtr)
  Else
    Err.Raise 5, , "Variant must contain array of user defined type"
  End If
End Function


Public Function ArrayExists(ByVal ppArray As Long) As Long
  GetMem4 ppArray, VarPtr(ArrayExists)
End Function

Verwendung:

? ArrayExists(ArrPtr(someArray))
? ArrayExists(StrArrPtr(someArrayOfStrings))
? ArrayExists(UDTArrPtr(someArrayOfUDTs))

Ihr Code scheint dasselbe zu tun (Testen, ob SAFEARRAY ** NULL ist), aber in einer Weise, die ich als Compiler-Fehler betrachten würde :)


Mein einziges Problem mit API-Aufrufen ist die Umstellung von 32-Bit- auf 64-Bit-Betriebssysteme.
Dies funktioniert mit Objekten, Strings, etc ...

Public Function ArrayIsInitialized(ByRef arr As Variant) As Boolean
    On Error Resume Next
    ArrayIsInitialized = False
    If UBound(arr) >= 0 Then If Err.Number = 0 Then ArrayIsInitialized = True
End Function

In VB6 gibt es eine Funktion namens "IsArray", aber es überprüft nicht, ob das Array initialisiert wurde. Wenn Sie versuchen, UBound für ein nicht initialisiertes Array zu verwenden, erhalten Sie Fehler 9 - Index außerhalb des Bereichs. Meine Methode ist der von S J sehr ähnlich, außer dass sie mit allen Variablentypen arbeitet und Fehler behandelt. Wenn eine Nicht-Array-Variable aktiviert ist, erhalten Sie Fehler 13 - Typenkonflikt.

Private Function IsArray(vTemp As Variant) As Boolean
    On Error GoTo ProcError
    Dim lTmp As Long

    lTmp = UBound(vTemp) ' Error would occur here

    IsArray = True: Exit Function
ProcError:
    'If error is something other than "Subscript
    'out of range", then display the error
    If Not Err.Number = 9 Then Err.Raise (Err.Number)
End Function

Basierend auf all den Informationen, die ich in diesem existierenden Beitrag gelesen habe, funktioniert dies am besten für mich, wenn es sich um ein typisiertes Array handelt, das als nicht initialisiert startet.

Es hält den Testcode konsistent mit der Verwendung von UBOUND und erfordert keine Fehlerbehandlung zum Testen.

Es ist abhängig von Zero Based Arrays (was in den meisten Fällen der Fall ist).

Verwenden Sie nicht "Löschen", um das Array zu löschen. Verwenden Sie die unten aufgelistete Alternative.

Dim data() as string ' creates the untestable holder.
data = Split(vbNullString, ",") ' causes array to return ubound(data) = -1
If Ubound(data)=-1 then ' has no contents
    ' do something
End If
redim preserve data(Ubound(data)+1) ' works to increase array size regardless of it being empty or not.

data = Split(vbNullString, ",") ' MUST use this to clear the array again.

Sie können das Problem mit der Ubound() Funktion lösen, überprüfen, ob das Array leer ist, indem Sie die Gesamtzahl der Elemente mit dem JScript- VBArray() -Objekt VBArray() (funktioniert mit Arrays vom Variant-Typ, einfach oder mehrdimensional):

Sub Test()

    Dim a() As Variant
    Dim b As Variant
    Dim c As Long

    ' Uninitialized array of variant
    ' MsgBox UBound(a) ' gives 'Subscript out of range' error
    MsgBox GetElementsCount(a) ' 0

    ' Variant containing an empty array
    b = Array()
    MsgBox GetElementsCount(b) ' 0

    ' Any other types, eg Long or not Variant type arrays
    MsgBox GetElementsCount(c) ' -1

End Sub

Function GetElementsCount(aSample) As Long

    Static oHtmlfile As Object ' instantiate once

    If oHtmlfile Is Nothing Then
        Set oHtmlfile = CreateObject("htmlfile")
        oHtmlfile.parentWindow.execScript ("function arrlength(arr) {try {return (new VBArray(arr)).toArray().length} catch(e) {return -1}}"), "jscript"
    End If
    GetElementsCount = oHtmlfile.parentWindow.arrlength(aSample)

End Function

Für mich dauert es etwa 0,4 mkSek für jedes Element + 100 ms Initialisierung, die mit VB 6.0.9782 kompiliert werden, so dass die Anordnung von 10M Elementen etwa 4,1 Sekunden dauert. Die gleiche Funktionalität könnte über ScriptControl ActiveX implementiert werden.


Sie können dies versuchen:

var arr = []; (or) arr = new Array();
var obj = {}; (or) arr = new Object();

arr.constructor.prototype.hasOwnProperty('push') //true

obj.constructor.prototype.hasOwnProperty('push') // false




arrays vb6