Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort zur 6. Auflage
1 Allgemeine Einführung in .NET
2 Grundlagen der Sprache C#
3 Das Klassendesign
4 Vererbung, Polymorphie und Interfaces
5 Delegates und Ereignisse
6 Strukturen und Enumerationen
7 Fehlerbehandlung und Debugging
8 Auflistungsklassen (Collections)
9 Generics – Generische Datentypen
10 Weitere C#-Sprachfeatures
11 LINQ
12 Arbeiten mit Dateien und Streams
13 Binäre Serialisierung
14 XML
15 Multithreading und die Task Parallel Library (TPL)
16 Einige wichtige .NET-Klassen
17 Projektmanagement und Visual Studio 2012
18 Einführung in die WPF und XAML
19 WPF-Layout-Container
20 Fenster in der WPF
21 WPF-Steuerelemente
22 Elementbindungen
23 Konzepte von WPF
24 Datenbindung
25 Weitere Möglichkeiten der Datenbindung
26 Dependency Properties
27 Ereignisse in der WPF
28 WPF-Commands
29 Benutzerdefinierte Controls
30 2D-Grafik
31 ADO.NET – Verbindungsorientierte Objekte
32 ADO.NET – Das Command-Objekt
33 ADO.NET – Der SqlDataAdapter
34 ADO.NET – Daten im lokalen Speicher
35 ADO.NET – Aktualisieren der Datenbank
36 Stark typisierte DataSets
37 Einführung in das ADO.NET Entity Framework
38 Datenabfragen des Entity Data Models (EDM)
39 Entitätsaktualisierung und Zustandsverwaltung
40 Konflikte behandeln
41 Plain Old CLR Objects (POCOs)
Stichwort

Download:
- Beispiele, ca. 62,4 MB

Jetzt Buch bestellen
Ihre Meinung?

Spacer
Visual C# 2012 von Andreas Kühnel
Das umfassende Handbuch
Buch: Visual C# 2012

Visual C# 2012
Rheinwerk Computing
1402 S., 6., aktualisierte und erweiterte Auflage 2013, geb., mit DVD
49,90 Euro, ISBN 978-3-8362-1997-6
Pfeil 2 Grundlagen der Sprache C#
Pfeil 2.1 Konsolenanwendungen
Pfeil 2.1.1 Allgemeine Anmerkungen
Pfeil 2.1.2 Ein erstes Konsolenprogramm
Pfeil 2.2 Grundlagen der C#-Syntax
Pfeil 2.2.1 Kennzeichnen, dass eine Anweisung abgeschlossen ist
Pfeil 2.2.2 Anweisungs- und Gliederungsblöcke
Pfeil 2.2.3 Kommentare
Pfeil 2.2.4 Die Groß- und Kleinschreibung
Pfeil 2.2.5 Die Struktur einer Konsolenanwendung
Pfeil 2.3 Variablen und Datentypen
Pfeil 2.3.1 Variablendeklaration
Pfeil 2.3.2 Der Variablenbezeichner
Pfeil 2.3.3 Der Zugriff auf eine Variable
Pfeil 2.3.4 Ein- und Ausgabemethoden der Klasse »Console«
Pfeil 2.3.5 Die einfachen Datentypen
Pfeil 2.3.6 Typkonvertierung
Pfeil 2.4 Operatoren
Pfeil 2.4.1 Arithmetische Operatoren
Pfeil 2.4.2 Vergleichsoperatoren
Pfeil 2.4.3 Logische Operatoren
Pfeil 2.4.4 Bitweise Operatoren
Pfeil 2.4.5 Zuweisungsoperatoren
Pfeil 2.4.6 Stringverkettung
Pfeil 2.4.7 Sonstige Operatoren
Pfeil 2.4.8 Operator-Vorrangregeln
Pfeil 2.5 Datenfelder (Arrays)
Pfeil 2.5.1 Die Deklaration und Initialisierung eines Arrays
Pfeil 2.5.2 Der Zugriff auf die Array-Elemente
Pfeil 2.5.3 Mehrdimensionale Arrays
Pfeil 2.5.4 Festlegen der Array-Größe zur Laufzeit
Pfeil 2.5.5 Bestimmung der Array-Obergrenze
Pfeil 2.5.6 Die Gesamtanzahl der Array-Elemente
Pfeil 2.5.7 Verzweigte Arrays
Pfeil 2.6 Kontrollstrukturen
Pfeil 2.6.1 Die »if«-Anweisung
Pfeil 2.6.2 Das »switch«-Statement
Pfeil 2.7 Programmschleifen
Pfeil 2.7.1 Die »for«-Schleife
Pfeil 2.7.2 Die »foreach«-Schleife
Pfeil 2.7.3 Die »do«- und die »while«-Schleife

Rheinwerk Computing - Zum Seitenanfang

2.7 ProgrammschleifenZur nächsten Überschrift

Schleifen dienen dazu, Anweisungsfolgen wiederholt auszuführen. Dabei wird zwischen zwei Schleifentypen unterschieden:

  • bestimmte Schleifen
  • unbestimmte Schleifen

Ist beim Schleifeneintritt bekannt, wie oft die Anweisungsfolge durchlaufen werden muss, wird von einer bestimmten Schleife gesprochen. Ergibt sich erst während des Schleifendurchlaufs, wann die zyklische Bearbeitung abgebrochen werden kann oder muss, spricht man von unbestimmten Schleifen. Die Grenzen zwischen diesen beiden Typen sind dabei nicht eindeutig, sondern können durchaus verwischen. Eine bestimmte Schleife kann wie eine unbestimmte agieren, eine unbestimmte wie eine bestimmte.


Rheinwerk Computing - Zum Seitenanfang

2.7.1 Die »for«-SchleifeZur nächsten ÜberschriftZur vorigen Überschrift

Man setzt eine for-Schleife meistens dann ein, wenn bekannt ist, wie oft bestimmte Anweisungen ausgeführt werden müssen. Die allgemeine Syntax des for-Schleifenkonstrukts sieht dabei wie folgt aus:

for(Ausdruck1; Ausdruck2; Ausdruck3)
{
// Anweisungen
}

Die for-Schleife setzt sich aus zwei Komponenten zusammen: aus dem Schleifenkopf, der die Eigenschaft der Schleife beschreibt, und aus dem sich daran anschließenden Schleifenblock in geschweiften Klammern, der die wiederholt auszuführenden Anweisungen enthält. Handelt es sich dabei nur um eine Anweisung, kann auf die geschweiften Klammern verzichtet werden. Um die Anzahl der Durchläufe einer for-Schleife festzulegen, bedarf es eines Schleifenzählers, dessen Anfangswert durch Ausdruck1 beschrieben wird. Der Endwert wird im Ausdruck2 festgelegt, und im Ausdruck3 wird schließlich bestimmt, auf welchen Betrag der Schleifenzähler bei jedem Schleifendurchlauf erhöht werden soll. Dazu ein Beispiel:

for(int counter = 0; counter < 10; counter++) {
Console.WriteLine("Zählerstand = {0}",counter);
}

Listing 2.30 Konstruktion einer einfachen »for«-Schleife

Der Schleifenzähler heißt hier counter. Sein Startwert beträgt 0, und er wird bei jedem Schleifendurchlauf um den Wert 1 erhöht. Erreicht counter den Wert 10, wird das Programm mit der Anweisung fortgesetzt, die dem Anweisungsblock der Schleife folgt.

Führen wir den Code aus, werden wir an der Konsole die folgende Ausgabe erhalten:

Zählerstand = 0
Zählerstand = 1
Zählerstand = 2
Zählerstand = 3
[...]
Zählerstand = 8
Zählerstand = 9

Weil der Schleifenblock nur eine Anweisung enthält, könnte die for-Schleife auch wie folgt codiert werden:

for(int counter = 0; counter < 10; counter++)
Console.WriteLine("Zählerstand = {0}",counter);

Die Arbeitsweise der »for«-Schleife

Stößt der Programmablauf auf eine for-Schleife, wird zuerst Ausdruck1 – auch Initialisierungsausdruck genannt – ausgewertet. Dieser initialisiert den Zähler der Schleife mit einem Startwert. Der Zähler der Schleife in unserem Beispiel wird mit dem Startwert 0 initialisiert.

Ausdruck2, der Bedingungsausdruck, wertet vor jedem Schleifendurchlauf den aktuellen Stand des Zählers aus. Im Beispiel von oben lautet die Bedingung:

counter < 10

Der Bedingungsausdruck kann unter Einbeziehung der diversen Operatoren beliebig komplex werden, muss aber immer ein boolesches Ergebnis haben. Der Anweisungsblock wird nur dann ausgeführt, wenn Ausdruck2 true ist, ansonsten setzt das Programm seine Ausführung mit der Anweisung fort, die dem Schleifenblock folgt.

Ausdruck3 (Reinitialisierungsausdruck) übernimmt die Steuerung des Schleifenzählers. Er wird dazu benutzt, den Schleifenzähler entweder zu inkrementieren oder zu dekrementieren. In unserem Fall wird der Zähler jeweils um +1 erhöht. Die Erhöhung erfolgt immer dann, wenn der Anweisungsblock der Schleife durchlaufen ist. Danach bewertet der Bedingungsausdruck den neuen Zählerstand.

Die Zählervariable

Grundsätzlich gibt es zwei Möglichkeiten, die Zählervariable zu deklarieren, die für das Abbruchkriterium herangezogen wird:

  • innerhalb des Schleifenkopfs
  • vor der Schleife

Welcher Notation Sie den Vorzug geben, hängt davon ab, über welche Sichtbarkeit der Zähler verfügen soll. Betrachten Sie dazu zunächst das folgende Codefragment:

static void Main(string[] args) {
for(int index = 0; index <= 10 ;index++) {
Console.WriteLine("Zählerstand = {0}",index);
}
// die folgende Codezeile verursacht einen Kompilierfehler
Console.WriteLine(index);
}

Listing 2.31 Deklaration der Zählervariablen im Schleifenkopf

Eine Zählervariable, die im Schleifenkopf deklariert wird, gilt als lokale Variable der Schleife und ist deshalb auch nur innerhalb des Anweisungsblocks der for-Schleife gültig. Der Zugriff auf den Zähler von außerhalb der Schleife führt deshalb auch zu einem Kompilierfehler.

Implementieren Sie innerhalb einer Prozedur wie Main mehrere Schleifen, müssen Sie daher auch jedes Mal den Zähler neu deklarieren:

static void Main(string[] args) {
for(int index = 0; index <= 10 ;index++) {}
[...]
for(int index = 12; index <= 100 ;index += 3){}
}

Die bessere Lösung wäre in diesem Fall die Deklaration der Zählervariablen vor dem Auftreten der ersten Schleife:

int index;
for(index = 0; index <= 10 ;index++) { [...] }
for(index = 12; index <= 100 ;index += 3){ [...] }

Wenn wir an diesem Punkt angekommen sind, stellt sich jetzt die Frage, ob beim Vorliegen einer einzigen for-Schleife die gleichzeitige Deklaration und Initialisierung im Schleifenkopf der vorgezogenen Deklaration der Zählervariablen vor dem Schleifenkopf vorzuziehen ist. Eine klare Antwort darauf gibt es nicht. Der besseren Übersichtlichkeit wegen scheint es jedoch vorteilhaft zu sein, die Deklaration im Initialisierungsausdruck vorzunehmen.

»for«-Schleifen mit beliebiger Veränderung des Zählers

In den meisten Fällen erfüllt eine ganzzahlige Schrittweite die Anforderungen vollkommen. Das ist aber nicht immer so. Manchmal werden auch kleinere Schrittweiten benötigt, also im Bereich von Fließkommazahlen. Fließkommazahlen sind naturgemäß systembedingt immer ungenau. Das kann bei Schleifen besonders fatale Folgen haben. Sehen Sie sich dazu das folgende Listing an:

static void Main(string[] args) {
int value = 0;
for(double counter = 0; counter <= 2 ;counter += 0.1) {
value++;
Console.WriteLine("{0}. Zählerstand = {1}", value, counter);
}
Console.ReadLine();
}

Listing 2.32 »for«-Schleife mit Zähler vom Typ einer Dezimalzahl

Normalerweise würden wir auf den ersten Blick keinen Haken vermuten – erst wenn wir das Programm ausführen, werden wir feststellen, dass der letzte Zählerwert fehlt:

1. Zählerstand = 0
2. Zählerstand = 0,1
[...]
18. Zählerstand = 1,7
19. Zählerstand = 1,8
20. Zählerstand = 1,9

Die systembedingte Ungenauigkeit der Fließkommazahlen bewirkt, dass der Zählerstand im letzten Schritt nicht exakt 2 ist, sondern ein wenig größer. Damit wird der zweite Ausdruck des Schleifenkopfs zu false und bewirkt den vorzeitigen Ausstieg aus der Schleife – der letzte erforderliche Schleifendurchlauf wird überhaupt nicht ausgeführt.

Diese These lässt sich beweisen, wenn die Anweisung zur Ausgabe an der Konsole durch die folgende ersetzt wird:

Console.WriteLine("{0}. Zählerstand = {1:E16}", value, counter);

Wir erzwingen nun die Ausgabe in Exponentialschreibweise und geben eine Genauigkeit von 16 Nachkommastellen an – dann wird der Typ double an der 16. Nachkommastelle ungenau. Die Ausgabe an der Konsole sieht dann wie in Abbildung 2.7 gezeigt aus.

Abbildung

Abbildung 2.7 Fließkommazahl als Zähler – die Ausgabe an der Konsole

Dieser Fehler kann vermieden werden, wenn sowohl der Zähler als auch die Schrittweite ganzzahlig gemacht werden. In unserem Beispiel wird mit dem Faktor 10 die Schrittweite auf +1 gesetzt. Analog muss auch die Ausstiegsbedingung angepasst werden. Um den Effekt bei der Ausgabe wieder rückgängig zu machen, dividieren wir das auszugebende Datum am Ende durch denselben Faktor.

static void Main(string[] args) {
int value = 0;
for(double counter = 0; counter <= 20 ;counter++) {
value++;
Console.WriteLine("{0}. Zählerstand = {1}", value, counter/10);
}
Console.ReadLine();
}

Listing 2.33 Anpassung von Code in Listing 2.32 an Ganzzahlen

Natürlich bewirkt die Division ihrerseits auch wieder eine Ungenauigkeit, aber das liegt in der Natur der Fließkommazahlen, was wir akzeptieren müssen. Andererseits haben wir aber die Gewissheit, dass zumindest die Anzahl der Schleifendurchläufe korrekt ist.

Die Initialisierung von Arrays in einer »for«-Schleife

Sie haben gesehen, dass mit for-Schleifen Anweisungssequenzen wiederholt ausgeführt werden. Dieser Schleifentyp eignet sich besonders dazu, Array-Elemente mit bestimmten Werten zu initialisieren. Machen wir uns das an einem einfachen Beispiel deutlich. Das Array liste soll mit Zahlen initialisiert werden, die dem Quadrat des Index des Elements entsprechen. Den höchsten vertretenen Index soll der Anwender an der Konsole eingeben. Der Code dazu sieht wie folgt aus:

static void Main(string[] args) {
int[] liste;
Console.Write("Geben Sie den höchsten Array-Index ein: ");
liste = new int[Convert.ToInt32(Console.ReadLine()) + 1];
for(int i = 0; i < liste.Length; i++) {
liste[i] = i * i;
Console.WriteLine(liste[i]);
}
Console.ReadLine();
}

Listing 2.34 Ein Array in einer Schleife initialisieren

Nach der Deklaration des Arrays und der sich anschließenden Aufforderung, die Größe des Arrays festzulegen, wird das Array entsprechend der Eingabe des Anwenders initialisiert. Die Anweisung dazu erscheint im ersten Moment verhältnismäßig komplex, ist aber recht einfach zu interpretieren. Dabei geht man – genauso wie es auch die Laufzeit macht – von der innersten Klammerebene aus, im vorliegenden Fall also von der Entgegennahme der Benutzereingabe:

Console.ReadLine()

Die Eingabe des Anwenders ist eine Zeichenfolge, also vom Typ string. Da die Indexangabe eines Arrays immer ein int sein muss, sind wir zu einer Konvertierung gezwungen:

Convert.ToInt32(Console.ReadLine())

Jetzt gilt es noch zu bedenken, dass per Vorgabe die Eingabe den höchsten Index des Arrays darstellt, wir aber bei einer Array-Initialisierung immer die Anzahl der Elemente angeben. Um unser Array endgültig richtig zu dimensionieren, muss die konvertierte Benutzereingabe noch um 1 erhöht werden, also:

Convert.ToInt32(Console.ReadLine()) + 1

Mit der daraus resultierenden Zahl kann das Array nun endgültig in der vom Anwender gewünschten Kapazität initialisiert werden.

Jetzt folgt die for-Schleife. Da wir jedem Array-Element im Schleifenblock das Quadrat seines Index zuweisen wollen, lassen wir den Schleifenzähler über alle vertretenen Indizes laufen – also von 0 bis zum höchsten Index. Letzteren ermitteln wir aus der Eigenschaft Length unseres Arrays, die uns die Gesamtanzahl der Elemente liefert. Diese ist immer um 1 höher als der letzte Index im Array. Daher entspricht die Bedingung

i < myArr.Length

immer den Forderungen, denn die Schleife wird jetzt so lange durchlaufen, bis die Zahl erreicht ist, die kleiner ist als die Anzahl der Elemente. Gleichwertig könnten wir auch Folgendes formulieren:

i <= liste.Length - 1

Der Schleifenkopf ist nun anforderungsgerecht formuliert, die Anweisungen des Schleifenblocks werden genauso oft durchlaufen, wie das Array Elemente aufweist. Da bei jedem Schleifendurchlauf der Schleifenzähler ein Pendant in Form eines Array-Index aufweist, können wir den Zähler dazu benutzen, jedes einzelne Array-Element anzusprechen:

liste[i] = i * i;

Beim ersten Durchlauf mit i = 0 wird demnach liste[0] die Zahl 0 zugewiesen, beim zweiten Durchlauf mit i = 1 dem Element liste[1] der Wert 1 usw.

Die Argumente der »Main«-Prozedur

Bisher haben wir unsere Programme immer nur durch einen einfachen Aufruf gestartet, entweder direkt aus der Entwicklungsumgebung heraus oder durch die Angabe des Dateinamens an der Eingabekonsole. Verteilen wir eine Anwendung, wird ein Anwender jedoch niemals aus der Entwicklungsumgebung heraus die Applikation starten, sondern entweder durch Doppelklick auf die EXE-Datei im Explorer, durch die Eingabe des Namens der ausführbaren Datei an der Eingabekonsole oder über die Option Start Ausführen...

Die beiden letztgenannten Punkte eröffnen noch weitere Möglichkeiten: Es können der Main-Methode auch Befehlszeilenparameter als zusätzliche Informationen übergeben werden, die im Array args der Parameterliste der Main-Methode entgegengenommen werden:

static void Main(string[] args)

Nehmen wir an, wir würden eine Anwendung namens MyApplication.exe an der Konsole wie folgt starten:

MyApplication Peter Willi Udo

Die drei Übergabeparameter »Peter«, »Willi« und »Udo« werden von Main im string-Array args empfangen und können von der Anwendung für weitere Operationen benutzt werden. Da das Programm zur Laufzeit jedoch nicht weiß, ob und wie viele Parameter übergeben worden sind, wird das Array args zunächst dahingehend abgefragt, ob überhaupt ein gültiges Element enthalten ist. Wenn die Anzahl der Elemente größer 0 ist, kann mit einer for-Schleife in bekannter Weise auf jedes Array-Element zugegriffen werden. Sehen wir uns das an einem konkreten Beispiel an:

// Beispiel: ..\Kapitel 2\Befehlszeilenparameter
class Program {
static void Main(string[] args)
{
// Prüfen, ob beim Programmaufruf eine oder mehrere
// Zeichenfolgen übergeben worden sind
if(args.Length > 0) {
// die Zeichenfolgen an der Konsole anzeigen
for(int i = 0; i < args.Length; i++)
Console.WriteLine(args[i]);
}
else
Console.WriteLine("Kein Übergabestring");
Console.ReadLine();
}
}

Listing 2.35 Auswerten der Übergabeargumente an die Methode »Main«

Das if-Statement stellt durch Auswertung der Length-Eigenschaft auf args fest, ob das Array leer ist oder nicht. Hat der Anwender zumindest einen Parameter übergeben, wird die for-Schleife ausgeführt, die den Inhalt des Parameters an der Konsole ausgibt.

Grundsätzlich werden alle übergebenen Parameter als Zeichenfolgen empfangen. Das soll uns aber nicht davon abhalten, im Bedarfsfall der Laufzeitumgebung auch Zahlen zu übergeben. Allerdings dürfen wir dann nicht vergessen, mit einer der Methoden der Klasse Convert die Zeichenfolge in den erforderlichen Datentyp zu konvertieren.

Verschachtelte Schleifen

for-Schleifen können praktisch beliebig verschachtelt werden. Im nächsten Beispiel wird gezeigt, wie eine verschachtelte Schleife dazu benutzt werden kann, einen Baum beliebiger Größe – hier durch Buchstaben dargestellt – an der Konsole auszugeben.

1:      M
2: MMM
3: MMMMM
4: MMMMMMM
5: MMMMMMMMM
6: MMMMMMMMMMM

Jede Ausgabezeile setzt sich aus einer Anzahl von Leerzeichen und Buchstaben zusammen und hängt von der Größe der Darstellung ab. Für die Leerzeichen gilt:

Anzahl Leerzeichen = Gesamtanzahl der Zeilen – aktuelle Zeilennummer

Die auszugebenden Buchstaben folgen der Beziehung:

Anzahl der Buchstaben = aktuelle Zeilennummer * 2 – 1

Um die gewünschte Ausgabe zu erhalten, wird in einer äußeren for-Schleife jede Stufe (Zeile) des Baums separat behandelt. Darin eingebettet sind zwei weitere Schleifen implementiert, von denen jede für sich zuerst vollständig ausgeführt wird – wir haben es also mit zwei parallelen inneren Schleifen zu tun. Dabei werden in der ersten inneren Schleife zuerst die Leerzeichen geschrieben und in der zweiten die Buchstaben. Die Struktur der Schleifen sieht demnach wie folgt aus:

// äußere Schleife beschreibt bei jedem Durchlauf eine Zeile
for(...) {
// Leerzeichen schreiben
for(...) {/*...*/}
// Buchstaben schreiben
for(...) {/*...*/}
}

Sehen wir uns nun den Programmcode an, der den gestellten Anforderungen genügt. Das Programm verlangt, dass der Anwender die Anzahl der Stufen als Befehlszeilenparameter angibt. Unterlässt er dies, wird das Programm mit einem entsprechenden Hinweis beendet.

// Beispiel: ..\Kapitel 2\Baumstruktur
class Program {
static void Main(string[] args)
{
// prüfen, ob das Array args leer ist
if(args.Length == 0)
{
Console.Write("Geben Sie beim Start der Anwendung ");
Console.Write("einen Parameter an.");
}
else
{
// das erste Element in den Typ int konvertieren
int zeile = Convert.ToInt32(args[0]);
// jede Stufe des Buchstabenbaums aufbauen
for(int i = 1; i <= zeile; i++)
{
// Leerzeichen schreiben
for(int j = 1; j <= zeile - i; j++)
Console.Write(" ");
// Buchstaben schreiben
for(int j = 1; j <= i * 2 - 1; j++)
Console.Write("M");
Console.WriteLine();
}
}
Console.ReadLine();
}
}

Listing 2.36 Verschachtelte »for«-Schleifen

Vorzeitiges Beenden einer Schleife mit »break«

Es kann sich zur Laufzeit als erforderlich erweisen, nicht auf das Erfüllen der Abbruchbedingung zu warten, sondern den Schleifendurchlauf vorzeitig zu beenden. C# stellt ein Schlüsselwort zur Verfügung, das uns dazu in die Lage versetzt: break.

for(int i = 0; i <= 10; i++) {
if(i == 3)
break;
Console.WriteLine("Zähler = {0}", i);
}

Listing 2.37 »for«-Schleife mit »break« vorzeitig abbrechen

Dieses Codefragment wird zu der folgenden Ausgabe an der Konsole führen:

Zähler = 0
Zähler = 1
Zähler = 2

break beendet die Schleife unabhängig von der im Schleifenkopf formulierten Abbruchbedingung und setzt den Programmablauf hinter dem Anweisungsblock der for-Schleife fort.

Sie können break auch in einer verschachtelten Schleife einsetzen. Das wirkt sich nur auf die for-Schleife aus, in deren direktem Anweisungsblock der Abbruch programmiert ist. Die äußeren Schleifen sind davon nicht betroffen.

Abbruch der Anweisungen im Schleifenblock mit »continue«

Sehr ähnlich wie break verhält sich auch die Anweisung continue. Die Bearbeitung des Codes in der Schleife wird zwar abgebrochen, aber die Steuerung wieder an den Schleifenkopf übergeben. Mit anderen Worten: Alle Anweisungen, die zwischen continue und dem Ende des Anweisungsblocks stehen, werden übersprungen. Das wollen wir uns ebenfalls an einem Codefragment ansehen:

for(int i = 0; i <= 10; i++) {
if(i == 3)
continue;
Console.WriteLine("Zähler = {0}", i);
}

Listing 2.38 Abbruch eines Schleifendurchlaufs mir »break«

Die Ausgabe an der Konsole sieht wie folgt aus:

Zähler = 0
Zähler = 1
Zähler = 2
Zähler = 4
Zähler = 5
[...]

Steht der Zähler auf 3, ist die Abbruchbedingung erfüllt. Es wird continue ausgeführt mit der Folge, dass die Laufzeitumgebung die folgende Ausgabeanweisung überspringt und die Schleife mit dem Zählerstand 4 fortgesetzt wird.

Die Ausdrücke der »for«-Schleife

Zum Abschluss der Ausführungen über die Möglichkeiten der for-Schleife unter C# kommen wir noch einmal auf die drei Ausdrücke im Schleifenkopf zurück. Was bisher noch nicht erwähnt worden ist, sei an dieser Stelle nachgeholt: Alle drei Ausdrücke sind optional, müssen also nicht angegeben werden. Fehlt aber ein Ausdruck, gilt dieser stets als »erfüllt«. Im Extremfall lässt sich eine Schleife sogar ganz ohne explizit ausformulierten Schleifenkopf konstruieren. Wir erhalten dann die kürzeste for-Schleife überhaupt – allerdings handelt es sich dann auch um eine Endlosschleife, da das Abbruchkriterium in dem Sinne als erfüllt gilt, dass die Schleife nicht beendet werden soll:

// Endlosschleife
for(;;);

Rheinwerk Computing - Zum Seitenanfang

2.7.2 Die »foreach«-SchleifeZur nächsten ÜberschriftZur vorigen Überschrift

Die for-Schleife setzt drei Ausdrücke voraus, die erst in Kombination die gewünschte Iteration ermöglichen. C# kennt noch ein weiteres Konstrukt, um ein Array vom ersten bis zum letzten Element zu durchlaufen: die foreach-Schleife. Sehen wir uns dazu ein Beispiel an, das genauso wie das oben gezeigte operiert:

int[] elements = {2,4,6,8};
foreach(int item in elements) {
Console.WriteLine(item);
}

Anstatt jedes Element über seinen Index anzusprechen, wird nun das Array als eine Einheit angesehen, die aus mehreren typgleichen Elementen gebildet wird. Das Array wird vom ersten bis zum letzten Mitglied durchlaufen, wobei die Adressierung nun über eine Laufvariable als temporäres Element erfolgt, das hier als item bezeichnet wird. Der Bezeichner ist natürlich frei wählbar. Bei der Iteration wird item jedes Mal auf ein anderes Array-Element verweisen. Daher ist die Indexangabe auch überflüssig.

Die allgemeine Syntax der foreach-Schleife lautet:

// Syntax: foreach-Schleife
foreach(Datentyp Bezeichner in Array-Bezeichner) { [...] }

Beachten Sie, dass die Deklaration der Laufvariablen in den Klammern nicht optional ist. Daher führt das folgende Codefragment zu einem Fehler:

int item;
// Fehler im foreach-Statement
foreach(item in intArr) { [...] }

Wenn Sie ein Array von Elementen eines einfachen Datentyps durchlaufen, sind die Daten schreibgeschützt, können also nicht verändert werden, z. B.:

int[] elements = {1,2,3,4,5};
foreach(int item in elements)
item = 33; // FEHLER !!

Möglicherweise lesen Sie diesen Hinweis erst, wenn Sie sich bereits beim Lesen dieses Buches in einem späteren Kapitel befinden. Daher muss ich an dieser Stelle der Vollständigkeit halber darauf hinweisen, dass ein Array nur schreibgeschützt ist, wenn es Wertetypen beschreibt. Zu diesen werden fast alle elementaren Datentypen gezählt. Ein Array von Objekten, die auf Referenztypen basieren, verhält sich anders: Die Objektdaten können durchaus in einer foreach-Schleife manipuliert werden. Für alle Leser, die noch nicht weiter in diesem Buch gelesen haben: Über Werte- und Referenztypen erfahren Sie alles Notwendige in Kapitel 3.


Rheinwerk Computing - Zum Seitenanfang

2.7.3 Die »do«- und die »while«-SchleifeZur nächsten ÜberschriftZur vorigen Überschrift

Ist die Anzahl der Iterationen bereits beim Eintritt in die Schleife bekannt, wird zumeist das for-Schleifenkonstrukt verwendet. Ergibt sich jedoch erst zur Laufzeit der Anwendung, wie oft der Schleifenkörper durchlaufen werden muss, bietet sich eher eine do- oder while-Schleife an. Grundsätzlich können alle auftretenden Anforderungen an wiederholt auszuführende Anweisungen mit einem dieser beiden Typen formuliert werden – sie können also die for-Schleife durchaus gleichwertig ersetzen.

Die »while«-Schleife

In eine Schleife wird dann eingetreten, wenn bestimmte Bedingungen erfüllt sind. Bei der for-Schleife wird diese Bedingung durch den Schleifenzähler festgelegt, bei einer while-Schleife wird die Bedingung hinter dem Schlüsselwort while in runden Klammern angegeben. Da sich die Anweisungen der Bedingungsprüfung anschließen, spricht man auch von einer kopfgesteuerten Schleife. Sehen wir uns daher zunächst die Syntax dieses Schleifentyps an:

while(Bedingung)
{
// Anweisungen
}

Bei der Bedingung handelt es sich um einen booleschen Ausdruck, der aus den Vergleichsoperatoren gebildet wird und entweder true oder false liefert. Eine while-Schleife wird ausgeführt, solange die Bedingung wahr, also true ist. Die Schleife wird beendet, wenn die Bedingung false ist. Ist die Bedingung schon bei der ersten Überprüfung falsch, werden die Anweisungen im Schleifenkörper überhaupt nicht ausgeführt.

Da im Gegensatz zur for-Schleife die Bedingung zum Austritt aus der while-Schleife nicht automatisch verändert wird, muss innerhalb des Schleifenkörpers eine Anweisung stehen, die es ermöglicht, die Schleife zu einem vordefinierten Zeitpunkt zu verlassen. Wenn Sie eine solche Anweisung vergessen, liegt der klassische Fall einer Endlosschleife vor.

Wenn Sie beim Testen eines Programms aus der Entwicklungsumgebung heraus in eine Endlosschleife geraten, können Sie mit der Tastenkombination Strg + Pause die Laufzeitumgebung unterbrechen und wieder zur Entwicklungsumgebung zurückkehren.

Im folgenden Beispiel muss der Anwender zur Laufzeit eine Zahl angeben, mit der er die Anzahl der Schleifendurchläufe festlegt. Die zusätzliche Zählervariable counter dient als Hilfsvariable, um die Austrittsbedingung zu formulieren. Sie wird innerhalb der Schleife bei jedem Schleifendurchlauf um 1 erhöht und bewirkt, dass die while-Schleife zum gewünschten Zeitpunkt verlassen wird.

// Beispiel: ..\Kapitel 2\WhileSample
class Program {
static void Main(string[] args)
{
Console.Write("Geben Sie eine Zahl zwischen\n");
Console.Write("0 und einschließlich 10 ein: ");
int number = Convert.ToInt32(Console.ReadLine());
int counter = 1;
while(counter <= number) {
Console.WriteLine("{0}.Schleifendurchlauf",counter);
// Änderung der Austrittsbedingung
counter++;
}
Console.ReadLine();
}
}

Listing 2.39 Beispielprogramm zu einer »while«-Schleife

Genauso wie eine for-Schleife kann auch eine while-Schleife entweder mit break oder mit continue unterbrochen werden. Die Auswirkungen sind bekannt:

  • Mit break wird die gesamte Schleife als beendet angesehen. Das Programm setzt seine Ausführung mit der Anweisung fort, die dem Anweisungsblock der Schleife folgt.
  • Mit continue wird der aktuelle Iterationsvorgang abgebrochen. Anweisungen, die innerhalb des Schleifenblocks auf continue folgen, werden nicht mehr ausgeführt. Die Steuerung wird an die Schleife zurückgegeben.

Daher würde das folgende Beispiel die Ausgabe 1,2 haben, während der Austausch von break gegen continue die Zahlenwerte 1,2, 4, 5 ausgibt.

int value = 0;
while(value < 5) {
value++;
if(value == 3)
break;
Console.WriteLine(value);
}

Die »do«-Schleife

Die do-Schleife unterscheidet sich dahingehend von der while-Schleife, dass die Schleifenbedingung am Ende der Schleife ausgewertet wird. Die do-Schleife ist eine fußgesteuerte Schleife. Die Folge ist, dass die Anweisungen innerhalb des Anweisungsblocks zumindest einmal durchlaufen werden.

do {
// Anweisungen
}while(<Bedingung>)

Der Anweisungsblock wird so lange wiederholt ausgeführt, bis die Bedingung false ist. Danach wird mit der Anweisung fortgefahren, die sich unmittelbar anschließt.

Die Tatsache, dass die Laufzeit einer Anwendung mindestens einmal in den Anweisungsblock der do-Schleife eintaucht, kann man sich zunutze machen, wenn eine bestimmte Eingabe vom Anwender erforderlich wird. Ist die Eingabe unzulässig, wird eine Schleife so lange durchlaufen, bis sich der Anwender »überzeugen« lässt. Im folgenden Beispiel wird das demonstriert.

// Beispiel: ..\Kapitel 2\DoSample
class Program {
static void Main(string[] args) {
// Informationsanzeige
Console.Write("W - Programm fortsetzen\n");
Console.Write("E - Programm beenden\n");
Console.Write("-----------------------\n");
// Schleife wird so oft durchlaufen, bis der Anwender
// eine gültige Eingabe macht
do {
Console.Write("Ihre Wahl: ");
string eingabe = Console.ReadLine();
if(eingabe == "W")
// das Programm nach dem Schleifenende fortsetzen
break;
else if(eingabe == "E")
// das Programm beenden
return;
else {
// Fehleingabe!
Console.Write("Falsche Eingabe - ");
Console.Write("Neueingabe erforderlich\n");
Console.Write("-----------------------\n");
}
} while(true);
Console.WriteLine("...es geht weiter.");
Console.ReadLine();
}
}

Listing 2.40 Beispiel zu einer »do«-Schleife

Zugelassen sind nur die beiden Eingaben »W« und »E«. Jede andere Eingabe führt zu einer erneuten Iteration. Die do-Schleife ist wegen ihrer Austrittsbedingung

while(true)

als Endlosschleife konstruiert, aus der es ein kontrolliertes Beenden nur mit der Sprunganweisung break gibt, wenn der Anwender mit der Eingabe »W« eine Fortsetzung des Programms wünscht.

Mit der Anweisung return wird das laufende Programm vorzeitig beendet. Diese Anweisung dient per Definition dazu, die aktuell ausgeführte Methode zu verlassen. Handelt es sich dabei aber um die Main-Methode einer Konsolenanwendung, kommt das dem Beenden der Anwendung gleich.



Ihre Meinung

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.

<< zurück
  Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Visual C# 2012

Visual C# 2012
Jetzt Buch bestellen


 Ihre Meinung?
Wie hat Ihnen das Openbook gefallen?
Ihre Meinung

 Buchempfehlungen
Zum Rheinwerk-Shop: Professionell entwickeln mit Visual C# 2012






 Professionell
 entwickeln mit
 Visual C# 2012


Zum Rheinwerk-Shop: Windows Presentation Foundation






 Windows Presentation
 Foundation


Zum Rheinwerk-Shop: Schrödinger programmiert C++






 Schrödinger
 programmiert C++


Zum Rheinwerk-Shop: C++ Handbuch






 C++ Handbuch


Zum Rheinwerk-Shop: C/C++






 C/C++


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo





Copyright © Rheinwerk Verlag GmbH 2013
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern