|
Schleifen in VB.Net
|
 |
|
Autor/Einsender: |
|
Thomas Becker |
|
|
|
Wir alle haben in unseren Programmen Schleifen integriert. Oft verlangt die Programmierung eine Überlegung, welche Schleifenform wann die Günstigste ist. Dabei können Schleifen mit durchdachter Bedingungsformulierung ebenso Objektmember liefern, Schritte überspringen oder gar rückwärts laufen. Aus diesen Grunde macht eine etwas tiefere Betrachtung Sinn, um
alle Möglichkeiten voll ausschöpfen zu können.
|
|
|
Zu jedem Schleifentyp sind
die besonderen Einsatzgebiete angeführt und werden anhand praktischer Beispiele
erläutert.
|
|
|
Die For/Next-Schleife ist eine beliebte Zählschleife. Sie ist sinnvoll einsetzbar wenn die Anzahl der Durchläufe bekannt ist. Außerdem erhält man einen Index. Eine Zahl, die sich mit jedem Durchlauf erhöht. Zudem kann man optional mittels
Step angeben, um wie viel Schritte sich der Index erhöht. Des weiteren kann die Variablendeklaration gleich im Schleifenkopf erfolgen. Es steht dem Entwickler frei, die Variable hinter
Next zu schreiben. Dies kann bei verschachtelten Schleifen nützlich sein.
|
Beispiel 1, Das Grundprinzip einer For-Schleife:
|
|
|
For i As Integer = 0 To 19 ' 20 Durchläufe
If ... Then Continue For
If ... Then Exit For
Next i
|
|
|
Alle Schleifenarten erlauben auch die Sprunganweisungen Continue und
Exit. Continue setzt die Schleife sofort ab nächsten Durchgang fort,
Exit bricht die aktuelle Schleife ab.
|
Im Gegensatz zu
GoTo-Sprungmarken gilt die Verwendung der Sprunganweisungen Continue und
Exit nicht als schlechter Stil, da diese in komplizierten Schleifen unvermeidbar sind.
|
Der Index sollte aus Performancegründen möglichst immer Integer sein. Prinzipiell ist aber auch ein anderer numerische Variablentyp zulässig. So ist Long und Decimal keine Hürde. Sehr vorsichtig sollte man mit reinen Gleitkomma-Werten (Single, Double) sein. Im folgenden Beispiel unterschlägt uns die Schleife deswegen einen ganzen Durchgang.
|
Beispiel 2, Gleitkommafehler der CPU:
|
|
|
For i As Single = 0 To 1 Step 0.05
MsgBox(i.ToString) 'Letzter Index nicht 1 sondern 0,9500002!
Next
|
|
|
Visual Basic verhält sich innerhalb der Schleife durchaus korrekt. 0,95 ist wegen dem CPU-Gleitkommafehler nun einmal nicht eins und ein weiterer
Step (Schritt) wäre > 1.
|
Damit sind wir auch schon bei Step gelandet. Wie sinnvoll das Auslassen von Schleifen-Schritten sein kann, soll der nächste Code verdeutlichen. Wir durchlaufen hier die Schleife in 2er Schritten. Dadurch können wir Felder aus einem Array in 2 verschiedene ListBoxen trennen.
|
Beispiel 3, Schleife befüllt in 2er-Schritten verschiedene ListBoxen aus einer
Quelle:
|
|
|
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e _
As System.EventArgs) Handles MyBase.Load
Dim MyArray() As String = New String() {"Heidelbeeren", _
"Cherimoya", "Gurken", "Curuba", "Pflaumen", "Durian", _
"Kirschen", "Datteln", "Himbeere", "Guave", "Birnen", _
"Mango", "Erdbeeren", "Papaya"}
For i As Integer = 0 To MyArray.GetUpperBound(0) Step 2
ListBox1.Items.Add(MyArray(i))
ListBox2.Items.Add(MyArray(i + 1))
Next
End Sub
End Class |
|
|
Im obigen Beispiel wird ein Stringarray, dass abwechselnd mit den Namen
heimischer sowie exotischen Früchte gefüllt ist, in einer Schleife
durchlaufen. Aufgrund der zweier Schritte (Step 2) der Schleife können nun immer 2
Datenfeld-Elemente (ArrayItems) an unterschiedliche Ziele übergeben werden. Dadurch werden die Sorten getrennt: Hiesige Früchte zur ListBox1, die Exoten zur ListBox2.
|
For/Next-Schleifen können auch rückwärts laufen, also vom größten
Index beginnend. Dazu sind lediglich die Werte am Schleifenkopf
umzudrehen sowie Step auf eine negative Zahl zu setzen.
|
Beispiel 4, Schleife läuft rückwärts durch Argb-Farben:
|
|
|
For i As Integer = 250 To 155 Step -1
Button1.BackColor = Color.FromArgb(i, i, i)
Threading.Thread.Sleep(10)
Button1.Refresh()
Next
|
|
|
Kombiniert mit einer ähnlichen Vorwärtsschleife bekommt der Button übrigens
einen interessanten Effekt.
|
|
|
Jedes Array sowie jede Collection lässt sich damit durchlaufen. Die Schleife wandert von einem Item zum anderen. Die Variable (nach "For Each") muss dem Typ des Items des zu durchlaufenen Arrays entsprechen. Ist es beispielsweise ein Integerarray, wird die Variable als Integer deklariert, da jedes Item ein Integerobjekt ist. Die Besonderheit ist, das wir beim Durchlauf jeweils ein Datenobjekt mit all seinen Methoden und Eigenschaften zur Verfügung haben.
|
Beispiel 5, Das Grundprinzip einer For Each-Schleife:
|
|
|
For Each printer As String In _
Printing.PrinterSettings.InstalledPrinters
If ... Then Continue For
If ... Then Exit For
Next
|
|
|
Beispiel 6, Durchlaufen eines Fileinfo-Objektes und Hinzufügen von Daten in eine ListBox:
|
|
|
Dim diPfad As New IO.DirectoryInfo("c:\windows")
For Each file As IO.FileInfo In diPfad.GetFiles()
ListBox1.Items.Add(file.Name.ToString & " " & _
file.LastWriteTime.ToShortDateString)
Next
|
|
|
Im obigen Beispiel wird ein GetFiles-Array
durchlaufen. Das jeweils von der Variable file bereitgestellte
FileInfo-Objekt wird genutzt, um deren Eigenschaften Name und
LastWriteTime auszulesen.
|
|
|
Als mit Abstand umfangreichstes Schleifenkonstrukt kann diese
Schleifenform angesehen werden und lässt präzise Bedingungsformulierung zu.
|
Beispiel 7, Das Grundprinzip einer Do/Loop-Schleife:
|
|
|
Do
If ... Then Continue Do
If ... Then Exit Do
Loop
|
|
|
Die Schleifenbedingung:
|
- Until (Ausführung bis [Anweisung]) oder
- While (Ausführung während [Anweisung])
- kann am Kopf oder Fuß der Schleife stehen
- Schleife ohne Bedingung ist ebenso zulässig
Beispiel 8, Die Do/Loop-Schleifenformen im Überblick:
|
|
|
=== Kopfbedingung Until ===
' Ende wenn Until-Bedingung den Schleifenkopf erreicht
Do Until ComboBox1.Items.Count > 90
=== Fußbedingung Until ===
' Ende wenn Until-Bedingung das Schleifenende erreicht
Loop Until ComboBox1.Items.Count > 90
=== Kopfbedingung While ===
' Läuft solange While-Bedingung am Schleifenkopf vorliegt
Do While ComboBox1.Items.Count > 90
=== Fußbedingung While ===
' Läuft solange While-Bedingung am Schleifenende vorliegt
Loop While ComboBox1.Items.Count > 90
|
|
|
Als Bedingung ist auch in einer Do/ Loop-Schleife alles erlaubt, was auch in If-Konstrukten formulierbar ist.
|
|
|
Die While-Schleife ist ein Konstrukt, indem eine Bedingung am Schleifenkopf festgelegt wird. Diese läuft dann solange während (engl. while) die Bedingung erfüllt ist. Im Gegensatz zu VB6 endet eine While-Schleife nicht mit Wend, sondern mit End While. Dies dient einer einheitlicheren Syntax. Wer dennoch Wend eingibt, dem wird die IDE von Visual Studio dies automatisch in die neue Schreibweise ändern.
|
Beispiel 9, Das Grundprinzip einer While-Schleife:
|
|
|
While ComboBox1.Items.Count < 90
If ... Then Continue While
If ... Then Exit While
End While
|
|
|
Als Bedingung kann praktisch alles verwendet werden was in If-Konstrukten erlaubt ist.
|
|
Kompakt: Verschachtelte Schleifen |
|
Grundsätzlich können Schleifen beliebig oft ineinander verschachtelt werden. Allerdings sollte man bedenken,
dass mit jeder zusätzlich verschachtelten Schleife die Gefahr von
Fehlern steigt, und diese im Schleifencode natürlich auch entsprechend schwerer
zu lokalisieren sind.
|
Beispiel 10, Grundprinzip Verschachtelung:
|
|
|
Dim i As Integer, k As Integer
'äußere Schleife
For k = 1 To 5
'erste innere Schleife
For i = 1 To 20
Next i
'zweite innere Schleife
For i = 1 To 20
Next i
Next k
'abschließende separate Schleife
For i = 1 To 20
Next i |
|
|
Anhand der automatischen Code-Einrückungen der Visual Studio-IDE kann
geprüft werden, ob die verschiedenen Schleifen richtig erkannt werden bzw. ob ein logischer Fehler vorliegen könnte. Man unterscheidet verschachtelte Schleifen in zwei Arten. Es gibt unabhängige und abhängige Verschachtelungen. Im nächsten Beispiel wird die Verschachtelungsart gezeigt, welche keine Auswirkung auf die innere Schleifenbedingung hat.
|
Beispiel 11, Verschachtelte unabhängige Schleife schreibt und liest ein 2-dimensionales Array:
|
|
|
Dim rows As Integer = 4
Dim cols As Integer = 4
Dim arr(rows - 1, cols - 1) As Integer
Dim row, col, i As Integer
For row = 0 To rows - 1
For col = 0 To cols - 1
arr(row, col) = i
i += 1
Next col
Next row
'2 dim. Array auslesen
For row = 0 To rows - 1
For col = 0 To cols - 1
MsgBox(arr(row, col))
Next col
Next row
|
|
|
Verschachtelungen können aber auch so gestaltet werden, das eine innere Schleife als Bedingung den Wert der Äußeren erhält. In diesem Falle spricht man von der abhängigen Verschachtelungsart.
|
Beispiel 12, Verschachtelte abhängige Schleife durchläuft Buchstaben:
|
|
|
Dim i As Integer, j As Integer, Ergebnis As String = ""
Dim Alphabet As String = "ABCDEFGH"
' äußere Schleife
For i = 0 To 7
' innere Schleife
For j = 0 To i '<- i ist auch hier im Einsatz!
Ergebnis += Alphabet.Chars(i)
Next j
Ergebnis += vbNewLine
Next i
MessageBox.Show(Ergebnis)
|
|
|
Die Variable Ergebnis erhält im obigen Beispiel folgenden Inhalt:
|
A
BB
CCC
DDDD
EEEEE
FFFFFF
GGGGGGG
HHHHHHHH
|
Möglich wird diese Abhängigkeit, da innere Schleifen von der Parentschleife immer wieder aufgerufen werden. Somit darf ihre Schleifenbedingung variieren.
|
|
Hinweise zum Einsatz in der Praxis |
|
Schleifen können bei längerer Durchlaufzeit zum Einfrieren der Form führen. In diesem Fall kann man mittels
Application.DoEvents ein Neuzeichnen der Form erzwingen. Dies verlangsamt jedoch den Schleifendurchlauf.
|
Beispiel 13, Neuzeichnen der überlasteten Form mit DoEvents:
|
|
|
For i As Integer = 1 To 2000
Label1.Text = i.ToString
Application.DoEvents() 'ohne DoEvents stockt die Form!
Next
|
|
|
Wesentlich besser ist es, die Schleife nach Möglichkeit in einem eigenen Thread (Stichwort: Multithreading) auszuführen. Dadurch wird der Formthread entlastet und so kann jederzeit die Form verschoben werden und reagiert problemlos auf weitere Benutzereingaben. Somit kann diese Schleifenprozedur mittels Abbruch-Button beendet werden.
|
Beispiel 14, Schleife im Nebenthread "entsperrt" die überlastete Form und lässt so einen vorzeitigen Abbruch
zu:
|
|
|
Imports System.Threading
Public Class Form1
Delegate Sub UpdateLabel(ByVal Wert As String)
Dim T As Thread, Counter As Integer
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e _
As System.EventArgs) Handles MyBase.Load
Button1.Text = "Starten"
Button2.Text = "Abbruch"
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e _
As System.EventArgs) Handles Button1.Click
Counter = 0
T = New Thread(AddressOf ThreadZiel)
T.Start()
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e _
As System.EventArgs) Handles Button2.Click
' Threadabbruch!
If T.ThreadState = ThreadState.WaitSleepJoin Or T.ThreadState = _
ThreadState.Running Then
T.Abort()
MsgBox("Vorzeitiger Thread-Abbruch bei " & Counter.ToString)
End If
End Sub
Private Sub ThreadZiel()
For i As Integer = 0 To 2000
Thread.Sleep(10)
Label1.BeginInvoke(New UpdateLabel(AddressOf LabelBearbeit), _
i.ToString)
Counter = i
Next
MsgBox("Normales Thread-Ende mit " & Counter.ToString)
End Sub
Private Sub LabelBearbeit(ByVal Wert As String)
Label1.Text = Wert
End Sub
End Class
|
|
|
Schleifen können schneller durchlaufen werden, indem man einen vorhandenen numerischen Index nicht oft verwendet. In langen Arrays und Collections verliert jeder wiederholte gleiche Indexaufruf wertvolle Rechenzeit, da das Item
jedes Mal erneut in der Auflistung gesucht werden muss. Da sollte man lieber beherzt zu einer zusätzlichen Variablen greifen, welcher lokal der Inhalt des Items zugewiesen wird.
|
Beispiel 15, Schleife ruft zu häufig ein ArrayIndex auf:
|
|
|
For i As Integer = 0 To StrArray.Length - 1
If StrArray(i).Contains("A") And StrArray(i) <> "" Then
StrArray(i) = StrArray(i).Replace("ABC", "")
StrArray(i) = StrArray(i).Insert(0, "123")
End If
Next
|
|
|
Beispiel 16, zusätzliche Variable verhindert ständigen Indexabruf:
|
|
|
Dim Wert As String
For i As Integer = 0 To StrArray.Length - 1
Wert = StrArray(i)
If Wert.Contains("A") And Wert <> "" Then
Wert = Wert.Replace("A", "")
Wert = Wert.Insert(0, "123")
End If
Next
|
|
|
In einer Schleife ist übrigens auch das Instanzieren einer Variable erlaubt. Diese Instanz gilt dann lokal für jeweils einen Schleifendurchgang und wird im neuen Durchgang automatisch erneuert.
|
Beispiel 17, eine in der Schleife instanzierte Variable behält ihren Wert nur im aktuellen
Durchgang:
|
|
|
Dim n As Integer = 10
For i As Integer = 1 To 3
Dim Labl As Label = New Label
Labl.Name = "Label" & i
Labl.Text = "Label" & i
Labl.Top = 100
Labl.Left = n
n += Labl.Width
Controls.Add(Labl)
Next
|
|
|
Um entsprechend einer Anforderung einen sauberen, übersichtlichen und schell ablaufenden Code zu
schreiben, verlangt es bei der Programmentwicklung oft die Überlegung, wann welche Schleifenform
am Besten eingesetzt werden soll. Dieses Tutorial zeigt auf und gibt einen Überblick, wie welche Schleifen verwendet werden können.
|
Natürlich erhebt es keinen Anspruch auf Vollständigkeit, und sollte es Ihrer Meinung nach an der ein oder anderen Stelle erweitert oder noch vertieft werden, geben Sie
einfach dem Autor Bescheid.
|
|
Bei Fragen zu diesem Tutorial nutzen Sie bitte unser VB.Net-Forum. |
|