05. september 2000 - 22:50Der 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
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\".
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.
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...
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.
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\" ???
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.
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.
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.
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.