Arbeiten mit .NET: C-Sharp/ Arbeitsablauf/ Kontrollstrukturen/ Kontrolle im Programm

Aus Wikibooks

Achtung, Baustelle! Dieses Buch wird zurzeit überarbeitet und in Arbeiten mit .NET eingegliedert.

Hinweise für Leser: Der Inhalt eines Kapitels passt unter Umständen nicht richtig zum Namen oder zur Gliederung. Gliederung und Inhaltsverzeichnis des Buches können vom Inhalt einzelner Kapitel abweichen. Verweise auf andere Kapitel können falsch sein.

Hinweis für Autoren: Bitte berücksichtigen Sie bereits jetzt die Konzeption der Buchreihe.


Kontrollstrukturen – ein Überblick[Bearbeiten]

Durch den Einsatz von Kontrollstrukturen kann auf den Ablauf eines Programms Einfluss genommen werden. In der Struktuierten Programmierung kennt man üblicherweise die folgenden Kontrollstrukturen:

  1. Reihenfolge (Folge, Sequenz, Aneinanderreihung)
  2. Auswahl (Selektion, Verzweigung, Entscheidung, bedingte Ausführung)
  3. Wiederholung (Iteration, Schleife, Loop)

Bei der Reihenfolge werden die notierten Anweisungen immer in der gleichen Reihenfolge ausgeführt. Bei der Auswahl kann die Fortführung des Programms auf mehreren alternativen Wegen erfolgen, immer aber in Richtung des Endes des Programms. Bei der Wiederholung kann im Gegensatz dazu die Fortsetzung des Programms an einer früher bereits durchlaufenen Stelle erfolgen, so dass ein „Rücksprung“ möglich ist.

Im Falle der Auswahl unterscheidet man üblicherweise drei Formen:

  1. Einseitige Auswahl
  2. Zweiseitige Auswahl
  3. Mehrseitige Auswahl (Fallunterscheidung)

Im Falle der Wiederholung kann man vier Formen unterscheiden:

  1. Abweisende Schleifen (pre-checked loop)
  2. Nicht abweisende Schleifen (post-checked loop)
  3. Zählschleife
  4. Iteration einer Auflistung (foreach)

Bedingte Ausführung[Bearbeiten]

Bedingte Ausführungen werden in Programmen sehr häufig benötigt. Sie sind dafür da, um die Möglichkeit zu haben, dem Computer klar zu machen: Wenn dies zutrifft, dann mache das.

if / else[Bearbeiten]

Allgemeine Syntax[Bearbeiten]

Für einzelne Anweisungen:

 if (Boolean) Anweisung;
 [else if (Boolean) Anweisung;]
 [else Anweisung;]

Für mehrere Anweisungen:

 if (Boolean)
 {
   Anweisungen;
 }
 [else if (Boolean)
 {
   Anweisungen;
 }]
 [else
 {
   Anweisungen;
 }]

Wie man sieht, wird hier der Datentyp Boolean (in C# mit bool abgekürzt) verwendet. Ein Boolean kann 2 Zustände annehmen: true (Wahr) oder false (Falsch). Mag auf den ersten Blick kompliziert klingen, ist es aber bei Leibe nicht, so etwas gibt es im Alltag auch: Wenn es regnet, öffne ich den Schirm:

using System;
public class Class1
{
	 public static void Main()
	 {
		 bool esRegnet = true;
		 //esRegnet = false;
		 if(esRegnet)
		 {
			 Console.WriteLine(„Ich mache den Regenschirm auf“);
		 }
		 Console.ReadLine();
	 }
}
Flussdiagramm zu obigen Programmierbeispiel

Das Programm gibt Ich mache den Regenschirm auf aus. Wenn man //esRegnet = false; wieder einkommentiert (die beiden // löschen), kommt es nicht zu dieser Ausgabe. Da man jetzt schon Wenn sagen kann, wäre doch ein Ansonsten recht nett, dies kann man mit else Erreichen:

using System;
public class Class1
{
	 public static void Main()
	 {
		bool esRegnet = true;
		//esRegnet = false;
		if(esRegnet)
		{
			Console.WriteLine(„Ich mache den Regenschirm auf“);
		}
		else
		{
			Console.WriteLine(„Ich lasse den Regenschirm zu“);
		}
		Console.ReadLine();
	}
}
Flussdiagramm zu obigen Programmierbeispiel

Es gibt allerdings auch Fälle, bei denen man beim else weitere Sachen abfragen will, z. B. könnte ja auch die Sonne scheinen:

using System;
public class Class1
{
	 public static void Main()
	 {
		bool sonneScheint = true;
		//sonneScheint = false;
		bool esRegnet = true;
		//esRegnet = false;
		if(sonneScheint)
		{
			Console.WriteLine(„Ich lasse den Regenschirm zuhause“);
		}
		else if(esRegnet)
		{
			Console.WriteLine(„Ich mache den Regenschirm auf“);
		}
		else
		{
			Console.WriteLine(„Ich nehme den Regenschirm mit“);
		}
		Console.ReadLine();
	}
}
Flussdiagramm zu obigen Programmierbeispiel

Nach diesen Beispielen sollte klar sein, was prinzipiell mit bedingter Ausführung gemeint ist. Da hierfür der Datentyp Boolean benötigt wird, wird der werte Leser bis zum besagten Kapitel für weitere Beispiele vertröstet.

switch / case[Bearbeiten]

Allgemeine Syntax:

switch (Variable)
{
	case Wert: Anweisungen break;
       [case Wert: Anweisungen break;]
       [default: Anweisungen break;]
}

C# benötigt eine explizite Fluss-Kontrolle. Deshalb muss darauf geachtet werden, dass am Ende jedes Falles (case) ein break steht. Ansonsten antwortet der C# Compiler mit dem Compilererror CS0163. Will man für einen Anweisungsblock mehrere Werte angeben, kann man dies in C# folgendermassen tun:

Mehrere Werte ohne Anweisungen:

switch (Variable)
{
	case Wert1:
	case Wert2: Anweisungen break;
       [case Wert3: Anweisungen break;]
       [default: Anweisungen break;]
}

Mehrere Werte mit Anweisungen:

switch (Variable)
{
	case Wert1: Anweisungen goto case Wert2;
	case Wert2: Anweisungen break;
       [case Wert3: Anweisungen break;]
       [default: Anweisungen break;]
}

Es können so viele Fälle angegeben werden wie gewünscht, allerdings keiner doppelt. Mit default ist für alle nicht erwähnten Fälle gemeint. Dieser ist optional. switch / case kann man eigentlich auch mit if/else darstellen, allerdings ist es nicht vorteilhaft, da es erstens unleserlicher ist und zweitens die Ausführung länger dauert, da beim switch / case eine Hashfunktion benutzt wird und so die Ausführung beschleunigt wird. Diese Hashfunktion benötigt allerdings Datentypen die der Compiler auch als konstant bewerten kann. switch / case ist aus diesem Grund auch nur für die Basisdatentypen und Enums erlaubt.

Folgendes Beispiel gibt die Zahlen 1,2,3 als Text aus:

using System;
public class SwitchCase
{
	public static void Main()
	{
		int i = 0;
		switch(i)
		{
			case 1: Console.WriteLine(„Eins“);break;
			case 2: Console.WriteLine(„Zwei“);break;
			case 3: Console.WriteLine(„Drei“);break;
			default: Console.WriteLine(„Die Zahl ist weder Eins, Zwei noch Drei“);break;
		}
                Console.ReadLine();
	}
}

Anmerkung: Mit int i = 0; wird eine Variable deklariert vom Typ int, welche ganze Zahlen darstellen kann. Gleichzeitig wird ihr der Wert 0 zugewiesen.

Wird das Programm so ausgeführt wie angegeben, wird der Fall default aufgerufen. Wenn man i einen Wert zuweist, welcher als Fall vorhanden ist, so wird diese Ausgabe getätigt. Dies kann z. B. erreicht werden, indem die Zeile int i = 0; durch int i = 1; ersetzt wird.

Schleifen[Bearbeiten]

Schleifen sind Konstrukte, mit denen man in einer Programmiersprache sagen kann: Durchlaufe diesen Teil öfters, z. B. eine gewisse Anzahl, oder solange etwas gilt.

While-Schleife[Bearbeiten]

Allgemeine Syntax:

while(Boolean)
{
   Anweisungen;
}

Damit kann man ausdrücken: Solange dies gilt, mache jenes. Eine Kaffeemaschine verhält sich z. B. so. Solange noch Wasser im Tank ist, heizt sie das Wasser, wenn der Tank leer ist, schaltet sie ab.

using System;
public class WhileBeispiel
{
	public static void  Main()
	{
		//Am Anfang sind noch 800 ml im tank
		int milliLiter = 800;
		//Solange noch Wasser im Tank
		while(milliLiter>0)
		{
			Console.WriteLine("Es sind noch " +milliLiter+ " ml im Tank,heize weiter!");
			//Heizen wir etwas Wasser
			milliLiter = milliLiter – 100;
		}
		Console.WriteLine(„Kaffe ist fertig,schalte ab“);
		Console.ReadLine();
	}
}

Anmerkungen: Der Ausdruck milliLiter = milliLiter - 100; ist nicht mathematisch zu verstehen, sondern muss so gelesen werden, dass milliLiter der Wert von milliLiter – 100 zugewiesen wird. Das bedeutet, dass nach diesem Ausdruck milliLiter einen um 100 niedrigeren Wert hat.

Was passiert hier? Bei der Whileschleife wird zu erst geprüft, ob die Bedingung gegeben ist, also ob der in Klammern stehende Boolean den Wert true besitzt. Auf den ersten Blick ist hier kein Boolean zu sehen, da er hier nicht explizit deklariert wird. Der Vergleich mit > ergibt allerdings einem Boolean, denn dieser kann ebenfalls nur Wahr oder Falsch sein.

Do – While – Schleife[Bearbeiten]

Allgemeine Syntax:

do
{
   Anweisungen;
}
while(Boolean);

Mit diesem Konstrukt kann man sagen: Mache etwas, solange dies gilt. Der Unterschied zur reinen Whileschleife ist, das hier der Code definitiv einmal durchlaufen wird. Auch hier werden wir wieder die Kaffeemaschine als Beispiel nehmen:

using System;
public class DoWhileBeispiel
{
	public static void  Main()
	{
		//Am Anfang sind noch 800 ml im tank
		int milliLiter = 800;
		//Solange noch Wasser im Tank
		do
		{
			Console.WriteLine("Es sind noch " +milliLiter+ " ml im Tank, heize weiter!");
			//Heizen wir etwas Wasser
			milliLiter = milliLiter – 100;
		}
		while(milliLiter>0);
		Console.WriteLine(„Kaffee ist fertig, schalte ab“);
		Console.ReadLine();
	}
}

In dieser Form macht dieses Programm das Selbe wie im vorherigen Beispiel. Wenn man jetzt allerdings bei beiden Beispielen die Zeile int milliLiter = 800; ändert in int milliLiter = 0;, wird der Unterschied deutlich. Bei der Whileschleife wird der Code nicht durchlaufen, bei der Dowhileschleife allerdings doch.

For-Schleife[Bearbeiten]

Allgemeine Syntax:

 for (Startausdruck; Gültigkeitsbedingung; Inkrementierungsausdruck)
 {
   Anweisungen;
 }

Die Forschleife wird in der Regel dann verwendet, wenn am Anfang schon gewusst wird, wie oft ein gewisser Code ausgeführt werden soll. Man kann dieses Konstrukt an sich auch mit einer Whileschleife ausdrücken, allerdings ist hierfür die Forschleife lesbarer. Hierfür soll uns ein Schultag als Grundlage dienen, als erstes durchgeführt durch eine Whileschleife:

using System;
public class WhileBeispiel
{
	public static void  Main()
	{
		//Wir beginnen mit der ersten Stunde
		int stunde = 1;
		//Solange der Schultag noch nicht zu Ende
		while(stunde<7)
		{
			Console.WriteLine("Ich habe gerade die " +stunde+ „. Stunde“);
			//Auf in die nächste stunde
			stunde++;
		}
		Console.WriteLine(„Mein Schultag ist zu Ende ;)“);
		Console.ReadLine();
	}
}

Anmerkungen: mit stunde++; wird der Inhalt von Stunde um eins inkrementiert. Sie ist mit dem Ausdruck stunde = stunde +1; equivalent.

So könnte man einen Schultag mit 6 Schulstunden darstellen. Auf den ersten Blick ist hier allerdings schwer zu erkennen, wie oft die Schleife durchlaufen wird. Anders bei der Forschleife:

using System;
public class ForBeispiel
{
	public static void  Main()
	{
		for(int stunde = 1; stunde<7; stunde++)
		{
			Console.WriteLine("Ich habe gerade die " +stunde+ „. Stunde“);
		}
		Console.WriteLine(„Mein Schultag ist zu Ende ;)“);
		Console.ReadLine();
	}
}

Hier sei angemerkt, dass die Variable stunde innerhalb der Forschleife gültig ist. Ihren Wert allerdings darin zu ändern gilt im Allgemeinen als schlechter Stil und sollte nur in Ausnahmefällen gemacht werden.

Foreach-Schleife[Bearbeiten]

Allgemeine Syntax:

 foreach (Typ Variablenname in IEnumerator)
 {
   Anweisungen;
 }

Die Foreach Schleife sei hier nur wegen der Vollständigkeit erwähnt, auf sie wird später, bei den Collections eingegangen.

Schleifensteuerung (break, continue)[Bearbeiten]

Bei Schleifen sind 2 Möglichkeiten vorhanden, sie weiter zu steuern. Diese 2 Möglichkeiten gelten für alle Schleifenkonstrukte. Sie sind bei verschachtelten Schleifen immer für die innerste Schleife gültig.

break[Bearbeiten]

Mit break kann die Abarbeitung einer Schleife vorzeitig abgebrochen werden.

using System;
public class BreakBeispiel
{
	public static void  Main()
	{
		for(int i = 1; i<10; i++)
		{
			Console.WriteLine("i hat den Wert: " +i);
			//Wenn i größer als 5 ist
			if (i>5)
			{
				break;
			}
			Console.WriteLine("i hat immer noch den Wert: " +i);
		}
		Console.WriteLine(„Programm ist zu Ende“);
		Console.ReadLine();
	}
}

Bei diesem Beispiel wird die Schleife nur fünf mal vollständig durchlaufen, beim sechsten Durchlauf wird die zweite Ausgabe nicht mehr gemacht, weil die Ausführung der Schleife mit break abgebrochen wird.

continue[Bearbeiten]

Mit continue kann innerhalb einer Schleife gesagt werden, dass ab hier der Durchlauf beendet sein soll, und wieder von vorne begonnen werden soll.

using System;
public class ContinueBeispiel
{
	public static void  Main()
	{
		for(int i = 1; i<10; i++)
		{
			Console.WriteLine("i hat den Wert: " +i);
			//Wenn i größer als 5 ist
			if (i>5)
			{
				continue;
			}
			Console.WriteLine("i hat immer noch den Wert: "+i);
		}
		Console.WriteLine(„Programm ist zu Ende“);
		Console.ReadLine();
	}
}

Bei diesem Beispiel wird die Schleife 9 mal ausgeführt, allerdings wird ab der sechsten Iteration die zweite Ausgabe nicht mehr gemacht. Sie wird übersprungen, weil mit continue die nächste Iteration gestartet wird.

Sprungbefehle[Bearbeiten]

goto[Bearbeiten]

  int a = 0;
  &nbsp;
  Top:
  if (a < 5)
  {
    ++a;
    goto Top;
  }
  Console.WriteLine("Ende des Programms");

Mit goto springt das Programm an die angegebene Markierung. goto wird jedoch nicht empfohlen, da es leicht 'Spaghetti-Code' erzeugt.

return[Bearbeiten]

  int result = QuadratVon(2);
  &nbsp;
  static int QuadratVon(int x)
  {
    int a;
    a = x*x;
    return a;
  }

Mit return wird die aktuelle Funktion verlassen und der im Kopf der Funktion vereinbarte Referenz- bzw. Datentyp als Rückgabewert zurückgeliefert. Funktionen ohne Rückgabewert werden mit void anstatt der Typangabe gekennzeichnet.

throw[Bearbeiten]

  File.openRead("Datei.txt");
  if (pos < 0) throw new AusnahmeDateiNichtGefunden();

Mit throw löst das Programm – vereinfacht gesagt – eine Fehlermeldung aus. Diese Fehler werden als Ausnahmen (Exceptions) bezeichnet und erlauben eine detaillierte und später sehr hilfreiche Behandlung von Fehlern während der Ausführung sowie Fehlern im Code.