Avatar billede winkill Nybegynder
05. september 2000 - 22:50 Der er 13 kommentarer og
1 løsning

Er arrayet initialiseret ?!?

Ok, jeg har et array (Dim myArray() As Boolean) og jeg har brug for at vide om det er initialiseret med ReDim myArray(0 To X) så jeg ikke får fejlen \"Subscript out of range\".

Jeg har checket med MSDN og kan kun finde to ringe måder at gøre dette på.

1) Ved at declare arrayet som variant kan man med funktionen IsArray checke om arrayet er en variant eller en variant der indeholder et array

2) Ved brug af en statisk boolean som er falsk ind til arrayet bliver initialiseret med ReDim

Er der ikke en smartere måde ???
Avatar billede tomasc Nybegynder
05. september 2000 - 23:10 #1
Husk at du altid kan bruge \"On Error GoTo\" - og i mange situationer er det den eneste (farbare) mulighed for at \"redde\" dig ud at en kedelig situation!

Hvad med at lave en funktion:

Private Function ArrInitialised(ByRef Arr As Variant)
    Dim lngLbound As Long
    On Error GoTo UnInitialised
    lngLbound = LBound(Arr)
    ArrInitialised = True
    Exit Function
UnInitialised:
    ArrInitialised = False
End Function

Som du kan bruge således:

    Dim myArray()  As Boolean
    Dim myVar      As Boolean
    MsgBox ArrInitialised(myArray)
    ReDim myArray(-1 To 7)
    MsgBox ArrInitialised(myArray)
    MsgBox ArrInitialised(myVar)

Skulle gerne returnere False, True, False.

Det er også let at udbygge funktionen til at returnere den \"ægte\" LBound eller en fast værdi (f.eks. -99999999) for at signalere \"ikke defineret\".
Avatar billede winkill Nybegynder
05. september 2000 - 23:23 #2
Jamen den funktion du har lavet tager jo godt og vel 5 gange så lang tid om at afgøre om et array er initialiseret.

Det skal jo netop maskinkraft der er problemet, ellers kunne jeg lige så godt bruge en variable.
Avatar billede tomasc Nybegynder
05. september 2000 - 23:26 #3
Den forstod jeg ikke.
Kører dir program for langsomt eller hvad?
Det skrev du ikke noget om indledningsvis.

Hvis du vil optimere, kan du jo indsætte On Error GoTo strukturen i din kode, dér hvor du skal checke dit array. Men det bliver ikke sjovt at vedligeholde.
Avatar billede winkill Nybegynder
06. september 2000 - 00:58 #4
Ok, helt presist skrav jeg \"Er der ikke en smartere måde ???\"

Hvad ser ud til at funke bedst:

If Not IsArray(varMinVariant) Then Bla bla bla.

eller

ArrInitialised(varDinVariant)

Private Function ArrInitialised(ByRef Arr As Variant)
    Dim lngLbound As Long
    On Error GoTo UnInitialised
    lngLbound = LBound(Arr)
    ArrInitialised = True
    Exit Function
UnInitialised:
    ArrInitialised = False
End Function

Det er ikke for at kritiserer eller noget, men jeg søger ikke en alternativ måde, med mindre den har en eller anden fordel...
Avatar billede tomasc Nybegynder
06. september 2000 - 09:19 #5
Hvis ikke af ArrInitialised er for langsom, ville jeg nok bruge den model. Jeg vil helst undgå Variant-typen, hvis det er muligt.

Du kan jo ændre funktionen, så den IKKE bruger varianter:

Private Function BooleanArrInitialised(ByRef BooleanArray() As Boolean) As Boolean

OBS: Jeg ser lige at jeg i min oprindelige definition glemte at angive funktionens returtype. VB lader den så automatisk returnere en Variant. Jeg ville have foretrukket en compileringsfejl...

Men meget indenfor programmering er jo en smagssag (synssag?), så i sidste ende er det din afgørelse. Men husk, at hvis du, hver gang du har brug for at gøre \"noget\", som kræver flere linie kode, og dette \"noget\" skal gøres tit, er det en god idé at pakke det ind i en procedure eller funktion.

Forresten forstod jeg ikke din kommentar som kritik, men jeg blev lidt forvirret og usikker på om jeg overhovedet havde forstået hvad du spurgte om.
Avatar billede winkill Nybegynder
06. september 2000 - 10:14 #6
Ok, problemet ligger i at jeg er ved at lave et webmail system i ASP, samme princip som hotmail, man opretter en e-mail adresse og bruger sin browser som e-mail program.
For at det kan lade sig gøre skal jeg bruge en mailserver, og da jeg ikke har råd til et licens til X antal brugere laver jeg selv min server - jeg ville oprindeligt have lavet den i c++ men jeg kan ikke få gang i winsock i det sprog.

For at holde styr på hvilke sockets der er loadet og hvilke der ikke er bruger jeg et array af boolean, som så skal redim\'es en gang i mellem.
Problemet opstår når der kommer ind indgående request fra en anden SMTP server. Så skal jeg nemmeligt åbne en ny socket til den forbindelse og dertil bliver jeg nød til at vide om mit array overhovedet er initialiseret - ellers får jeg jo en fejl når jeg bruger LBound/UBound.

Min løsning ind til nu har været som følger:


Private SckInUse() As Boolean
Private SckInUse_Init As Boolean

Function GrabSocket() As Winsock
\' Returner en ledig Winsock - bruges primært af session class\'en.
    Dim i As Integer
    If SckInUse_Init Then \' Hvis arrayet SckInUse er initialiseret
        For i = 1 To UBound(SckInUse) \' Check dette for alle hidtil brugte sockets
            If Not SckInUse(i) Then \' Hvis denne socket ikke bruges.
                SckInUse(i) = True \' Marker som værende \"I brug\"
                Call Load(frmVoid.Winsock(i)) \' Load det skidt
                Set GrabSocket = frmVoid.Winsock(i) \' Returner en pointer til denne socket
                Exit Function \' Thats it.
            End If
        Next i
        i = UBound(SckInUse) + 1 \' Bliver kun kørt hvis der ikke blev fundet en ledig socket.
    Else \' Hvis arrayet SckInUse IKKE er initialiseret
        i = 1 \' Så er det nok den første socket (1 = første)
        SckInUse_Init = True \' Så er mit array initialiseret
    End If
    ReDim Preserve SckInUse(0 To i) \' ReDim så der bliverr flere sockets at lege med
    SckInUse(i) = True \' Nu er denne socket altså i brug
    Call Load(frmVoid.Winsock(i)) \' Load den
    Set GrabSocket = frmVoid.Winsock(i) \' Returner svinet
End Function

Dette er lidt for kryptisk for VB og går dermed et par millisekunder for langsomt. Det må da kunne optimeres, og hvis man kunne skære en If/Else/EndIf af ville det sikkert give lidt ekstre \"kick\" i koden.

Derfor...

Er der en mere smart måde at gøre dette på ?

Konklutionen må vel være at det er der så længe der ikke er tale om at \"skære millisekunder væk\" ???


...Shit for en fristil.
Avatar billede tomasc Nybegynder
06. september 2000 - 10:29 #7
Hvis noget skal gå hurtigt, er det ikke en god idé at bruge for-next løkker til at søge med. Det er heller ikke godt at bruge ReDim Preserve - det tager tid.

Du kunne nemt eliminere ReDim Perserve ved fra starten af at dimme din tabel f.eks. fra 1 til 32000 (man kan højst loade ca. 32000 kontroller med samme navn).

For-next løkken er en anden sag. Jeg ville nok have en variabel, som kan huske højeste loadede socket (lad os kalde den H). Man kan så bruge en Collection eller et Dictionary (lad os kalde den or X)til at huske mængden af ledige sockets.

Når man har brug for en ny socket, checker man antallet i mængden X. Hvis den er 0, tælles H én op, og denne socket loades. Hvis mængden i X er større end 0, bruges blot socket X.Item(0) og item(0) fjernes fra mængden X. Det er naturligvis vigtigt at indsætte sockets i mængden X, når de bliver ledige.

Du kunne (måske) tilmed have en sideløbende task, som checker at når X.Count bliver mindre end f.eks. 10, begynder den at tæller H op og loade sockets, indtil X.Count bliver 10 eller højere. Blot en tanke.
Avatar billede winkill Nybegynder
06. september 2000 - 10:30 #8
Ok, nu har jeg så fundet et kompromis af en løsning som blive kørt allerede i min Sub Main.

Public Sub ForceInitialize()
    ReDim SckInUse(0 To 1)
End Sub

Dermed slipper jeg helt for at tænke på om arrayet er initialiseret.

Du skal nu have pointsne alligevel, det har vel taget lidt tid at sidde her og skrive og skrive ;-)
Avatar billede tomasc Nybegynder
06. september 2000 - 10:32 #9
Ja, med én finger af gangen tager det nu sin tid...
Avatar billede winkill Nybegynder
06. september 2000 - 10:34 #10
Hmmm, der var jeg vidst lige et sec. for hurtig.

Den med at smide ledige sockets i en collection var måske slet ikke så ringe endda. Jeg havde godt nok tænkt på at smide de brugte i en collection, men det giver jo ikke rigtigt nogen fordele.

Jeg ser lige om ikke det kan passe ind i resten af koden.
Avatar billede winkill Nybegynder
06. september 2000 - 10:35 #11
LOL
Avatar billede winkill Nybegynder
06. september 2000 - 10:45 #12
Damn, det var sq da en brillifant ide !!

Ok, her er så løsningen - som jeg ser det.

FreeSockets As Collection

Sub InitializeSockets(MaxSockets As Integer)
    Dim intCounter As Integer
    Set FreeSockets = New Collection
    While intCounter < MaxSockets
        i = i + 1
        Call Load(frmVoid.Winsock(intCounter))
        FreeSockets.Add frmVoid.Winsock(intCounter)
    Wend
End Sub

Function GrabSocket() As Winsock
    Set GrabSocket = FreeSockets.Item(1)
    FreeSockets.Remove(1)
End Function

Nu bliver hele arbejdet lavet i initialiseringsfasen og GrabSocket fylder nu kun 2 linier.

Tak, du er en helt tomasc.
Avatar billede winkill Nybegynder
06. september 2000 - 10:46 #13
Opret lige et svar så jeg kan smide points efter dig.
Avatar billede tomasc Nybegynder
06. september 2000 - 12:00 #14
Ifølge aftale: Et stk. svar.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester