Visual Basic .NET: Mehrseitige Entscheidungen
Oft sollen nicht nur einfache Ja/Nein- bzw. True/False-Entscheidungen getroffen werden, sondern mehrere Wege unterschieden werden. In Visual Basic .NET gibt es für solche mehrseitige Entscheidungen gleich zwei Lösungswege: einen bekannten, flexiblen und einen neuen und komfortablen.
Als Beispiel soll uns dieses Mal ein Würfelspiel dienen. Es werden zwei Würfel geworfen und die Augensumme gebildet. Es gilt folgender Spielplan:
Augensumme | Resultat |
---|---|
12 | 1. Preis |
10, 11 | 2. Preis |
7 - 9 | 3. Preis |
6 | Trostpreis |
2 - 5 | Niete |
Das Würfeln geschieht im Computer durch Zufallszahlen. Visual Basic .NET verfügt dazu über einen Zufallszahlengenerator auf Basis einer mathematischen Iterationsformel. Um den Generator zu initialisieren, genügt ein Aufruf der Funktion Randomize ohne Parameter. Dann gibt der Ausdruck Int(6 * Rnd() + 1)
eine Zufallszahl von 1 bis 6 zurück, der auf einer Variable gespeichert werden kann. Das Würfeln wird also wie folgt durchgeführt (wobei Meldungen über die Augenzahlen ausgegeben werden).
Randomize() Dim ErsterWuerfel As Integer = Int(6 * Rnd() + 1) Console.WriteLine("Der erste Würfel zeigt " & ErsterWuerfel & " Augen.") Dim ZweiterWuerfel As Integer = Int(6 * Rnd() + 1) Console.WriteLine("Der zweite Würfel zeigt " & ZweiterWuerfel & " Augen.") Dim Augensumme As Integer = ErsterWuerfel + ZweiterWuerfel Console.WriteLine("Die Augensumme beträgt " & Augensumme & ".")
(Beispiel, Zahlenwerte sind zufällig) Der erste Würfel zeigt 2 Augen. Der zweite Würfel zeigt 5 Augen. Die Augensumme beträgt 7.
Beachten Sie, dass der Ausdruck Int(6 * Rnd() + 1)
anders als die bisherigen Ausdrücke mit Werten und Operatoren nicht immer das gleiche zurückgibt. Das liegt an der Zufallsfunktion Rnd. Bei den Console.WriteLine-Aufrufen ist zu beachten, dass die Integer-Variablen für die Verkettungsoperation automatisch in Zeichenketten umgewandelt werden.
ElseIf
BearbeitenWas uns nun noch fehlt, ist eine Meldung über das Resultat, sprich was man gewonnen hat (wenn auch nur Ruhm und Ehre verlost werden). Versuchen Sie einmal selbst, mit dem bisherigen Wissen einen Code zu schreiben, der das Resultat feststellt und ausgibt. Wahrscheinlich werden Sie (mit leichten Abwandlungen) eine der folgenden zwei Möglichkeiten notieren. (Ich verzichte auf langatmige Ausgaben und gebe nur das direkte Resultat aus.)
If Augensumme = 12 Then Console.WriteLine("1. Preis") If Augensumme = 10 Or Augensumme = 11 Then Console.WriteLine("2. Preis") If Augensumme >= 7 And Augensumme <= 9 Then Console.WriteLine("3. Preis") If Augensumme = 6 Then Console.WriteLine("Trostpreis") If Augensumme < 6 Then Console.WriteLine("Niete")
3. Preis (für die Augensumme 7)
If Augensumme = 12 Then Console.WriteLine("1. Preis") Else If Augensumme >= 10 Then Console.WriteLine("2. Preis") Else If Augensumme >= 7 Then Console.WriteLine("3. Preis") Else If Augensumme = 6 Then Console.WriteLine("Trostpreis") Else Console.WriteLine("Niete") End If End If End If End If
3. Preis (für die Augensumme 7)
Im ersten Beispiel habe ich beim 3. Preis die Anzahl an Operationen reduziert, indem ich nicht Augensumme = 7 Or Augensumme = 8 Or Augensumme = 9
prüfe, sondern mir zunutze mache, dass die drei Werte einen zusammenhängenden Bereich bilden, sodass ich den aktuellen Wert nur mit der Obergrenze und mit der Untergrenze vergleichen muss. Ein Nachteil dieser Methode ist, dass unnötige Vergleiche durchgeführt werden. Angenommen, die Augensumme ist 12. Beim ersten Vergleich ist die Bedingung schon True, eine Meldung wird ausgegeben. Die anderen Vergleiche müssten jetzt eigentlich nicht mehr durchgeführt werden.
Das zweite Beispiel trägt dieser Problematik Rechnung. Es werden nur solange Vergleiche durchgeführt, bis ein Erfolg eintritt und eine Meldung ausgegeben wird. Dieses Beispiel ist vom Konzept her auch schon um einiges näher an der beabsichtigten Lösung, sieht nur sehr unübersichtlich aus. So sieht es richtig aus:
If Augensumme = 12 Then Console.WriteLine("1. Preis") ElseIf Augensumme >= 10 Then Console.WriteLine("2. Preis") ElseIf Augensumme >= 7 Then Console.WriteLine("3. Preis") ElseIf Augensumme = 6 Then Console.WriteLine("Trostpreis") Else Console.WriteLine("Niete") End If
3. Preis (für die Augensumme 7)
Das Schlüsselwort ElseIf leitet eine weitere Befehlsgruppe ein. Wenn die erste Bedingung nicht True ist, wird, sofern vorhanden, nicht in die Else-Gruppe, sondern zur ersten ElseIf-Bedingung gewechselt und diese ausgewertet. Ist diese Bedingung True, so wird die dazugehörige Befehlsgruppe ausgeführt. Ist die Bedingung False, wird sofern vorhanden, zur wiederum nächsten ElseIf-Bedingung gewechselt und diese ausgewertet. So geht das Verfahren immer weiter. Sobald eine Bedingung True ist, wird in die entsprechende Befehlsgruppe gewechselt und diese ausgeführt, dann wird ans Ende der If-Anweisung, hinter End If, gesprungen. Die verbleibenden, noch nicht geprüften Bedingungen, bleiben dann unberücksichtigt. Wurden alle Bedingungen negativ geprüft, wird in die Else-Gruppe gesprungen. Beachten Sie, dass die Else-Gruppe auch weggelassen werden kann, sie ist in einer If-Anweisung genauso optional wie die ElseIf-Gruppen.
Select
BearbeitenFür mehrseitige Anweisungen gibt es neben der erweiterten Form der If-Anweisung auch die sogenannte Select-Anweisung. Verwendet man anstatt der If-Anweisung die Select-Anweisung, ergibt sich für die Auswahl des Preises folgender Code. Beachten Sie, dass das Case-Schlüsselwort in der ersten Zeile optional ist, also auch weggelassen werden kann.
Select Case Augensumme Case 12 Console.WriteLine("1. Preis") Case 10, 11 Console.WriteLine("2. Preis") Case 7 To 9 Console.WriteLine("3. Preis") Case 6 Console.WriteLine("Trostpreis") Case Else Console.WriteLine("Niete") End Select
3. Preis (für die Augensumme 7)
Der Select-Anweisung wird in der ersten Zeile eine Variable zugeordnet, hier die Variable Augensumme. Im folgenden wird nur der Wert dieser Variablen mit bestimmten Werten verglichen. Die Bedingungen werden mit dem Schlüsselwort Case eingeleitet. Dann stehen die Werte, mit denen der Wert der Variablen verglichen werden soll. Geht einer dieser Vergleiche positiv aus, so werden die Befehle in der Befehlsgruppe, die auf die Bedingung folgt, ausgeführt, danach wird zur End Select-Anweisung gesprungen, welche die Select-Anweisung beschließt.
Die Syntax, die formale Notationsweise der mit Case eingeleiteten Bedingungen unterscheidet sich grundlegend von denen normaler Ausdrücke mit Bool'schen und Vergleichsoperatoren. Das Beispiel zeigt einige einfache Varianten.
In der ersten Bedingung Case 12
wird geprüft, ob der Wert der Variablen Augensumme gleich 12 ist. Das ergibt sich, so denke ich, auch aus dem Kontext. Man sieht, dass ein einfacher Vergleich durchgeführt wird, wenn nach Case nur ein Wert stehen. Die Select-Bedingung Case 12
entspricht der If-Bedingung Augensumme = 12
.
Die zweite Bedingung ähnelt der ersten, listet aber, durch Komma getrennt, mehrere Werte auf. Wenn der Wert der Variable Augensumme gleich einem dieser Werte ist, wird die zugeordnete Befehlsgruppe ausgeführt. Die Select-Bedingung Case 10, 11
entspricht der If-Bedingung (Augensumme = 10) Or (Augensumme = 11)
. Bei der Auflistung der Werte in der Select-Bedingung spielt die Reihenfolge keine Rolle.
In der dritten Bedingung Case 7 To 9
wird keine Liste von Werten definiert, sondern ein Bereich von Werten. Liegt der Wert der Variablen Augensumme innerhalb dieses Bereiches (wobei die Grenzen zum Bereich gehören), wird die der Select-Bedingung zugeordnete Befehlsgruppe ausgeführt. Diese Bedingung Case 7 To 9
entspricht also der If-Bedingung (Augensumme >= 7) And (Augensumme <= 9)
. Beachten Sie bei der Angabe von Bereichen, dass immer der kleinere Wert vor dem To stehen muss.
Sie können in einer Select-Bedingung auch mehrere Bereiche notieren und sie mit konkreten Werten verbinden. Diese einzelnen Elemente müssen lediglich durch Komma getrennt werden. Unten sehen Sie eine Beispielbedingung sowie die entsprechende If-Bedingung. Diese Codefragmente haben nichts mit dem Beispiel zu tun und dienen nur der Illustration. An diesem Beispiel sieht man etwa, dass Select-Bedingungen vor allem bei komplexen Vergleichen übersichtlicher sind.
Die vierte Select-Bedingung Case 6
entspricht inhaltlich offensichtlicherweise der ersten Bedingung.
Zuletzt finden wir mit Case Else
die Entsprechung zum Else-Schlüsselwort der If-Anweisung. Nur wenn vorher kein Vergleich positiv ausgegangen ist, wird die Case-Else-Befehlsgruppe ausgeführt.
Sie können das Beispiel auch kürzer schreiben, wenn Sie nach der jeweiligen Bedingung einen Doppelpunkt schreiben und dann in der gleichen Zeile den ersten Befehl der entsprechenden Befehlsgruppe notieren. Obgleich theoretisch immer einsetzbar, eignet sich diese Form in der Praxis aber aus Übersichtlichkeitsgründen nur für Befehlsgruppen, die nur aus einzelnen Befehlen bestehen, so wie in unserem Beispiel:
Select Augensumme Case 12 : Console.WriteLine("1. Preis") Case 10, 11 : Console.WriteLine("2. Preis") Case 7 To 9 : Console.WriteLine("3. Preis") Case 6 : Console.WriteLine("Trostpreis") Case Else : Console.WriteLine("Niete") End Select
3. Preis (für die Augensumme 7)
Verändern wir das Beispiel dahingehend, dass nur ausgegeben werden soll, ob ein Preis oder eine Niete aufgetreten ist.
Select Augensumme Case Is >= 6 : Console.WriteLine("Preis") Case Else : Console.WriteLine("Niete") End Select
Preis (für die Augensumme 7)
Die erste Bedingung hier enthält neben Werten und Bereichen die dritte Möglichkeit, den Wert zu vergleichen. Nach Case Is steht ein Vergleichsoperator und dessen rechter Operand, für den linken Operand wird der Wert von Augensumme eingesetzt. Die Select-Bedingung Case Is >= 6
entspricht also der If-Bedingung Augensumme >= 6
. Theoretisch ließen sich sämtliche Select-Bedingungen aus Is-Konstrukten zusammenbauen, wie die folgende Abwandlung der Preisauswahl zeigt:
Select Augensumme Case Is = 12 : Console.WriteLine("1. Preis") Case Is = 10, Is = 11 : Console.WriteLine("2. Preis") Case Is >= 7, Is <= 9 : Console.WriteLine("3. Preis") Case Is = 6 : Console.WriteLine("Trostpreis") Case Else : Console.WriteLine("Niete") End Select
3. Preis (für die Augensumme 7)
Ein solcher exzessiver Einsatz von Is-Konstrukten erzeugt allerdings einen schwer lesbaren Code und gehört dadurch nicht zum guten Programmierstil.
Die Select-Anweisung kann mit allen einfachen Datentypen, also mit allen Kommazahlen und mit Zeichenketten umgehen. Für Bereiche von Zeichenketten gelten dabei ähnliche Regeln wie für den Umgang von Vergleichsoperatoren mit Zeichenketten: Zuerst wird die Länge verglichen, dann werden gleichlange Zeichenketten alphabetisch sortiert und entsprechende Vergleiche durchgeführt.