ein Projekt von goloroden.de

Anweisungen

Bedingungen

Allen Beispielen in den vergangenen Kapiteln ist gemein, dass sie noch keine einzige Zeile Code enthalten, der im klassischen Sinn ausgeführt werden kann. Sämtliche Konzepte, die bislang thematisiert wurden, dienen lediglich der Modellierung und Strukturierung von Daten und Anwendungen. Sie bilden also nur den äußeren Rahmen für eine Anwendung, deren Inneres aber noch mit konkretem Code gefüllt und damit zum Leben erweckt werden muss.

Zur Steuerung des Ablaufs einer Anwendung gibt es in C# zwei wesentliche Konzepte: Bedingungen und Schleifen. Während Codeabschnitte mit Hilfe von Bedingungen nur unter bestimmten Umständen ausgeführt werden und die Ausführung dadurch dynamisch an den äußeren Kontext angepasst werden kann, dienen Schleifen der wiederholten Ausführung von Code, um beispielsweise eine Menge gleichartiger Daten zu verarbeiten.

Die einfachste Anweisung zur Abfrage einer Bedingung wurde im Kapitel zu Ereignissen bereits erwähnt, da dort überprüft werden musste, ob an den Delegaten eines Ereignisses überhaupt Methoden angehängt worden sind.

Der Anweisung if wird dabei in runden Klammern ein Ausdruck übergeben, der von C# ausgewertet und entweder zu true oder false evaluiert wird. Sofern der Ausdruck true ergibt, wird der Rumpf von if ausgeführt, andernfalls nicht.

In dem folgenden Beispiel wird also überprüft, ob der Storing-Delegat ungleich dem Literal null ist. Wenn dem so ist, wird der Rumpf ausgeführt und das entsprechende Ereignis ausgelöst.
C#
1
2
3
4
5
6
// Check if there are any event handlers.
if(this.Storing != null)
{
    // Raise the storing event.
    this.Storing(this, null);
}
Die geschweiften Klammern um den Rumpf sind optional, solange der Rumpf nur aus einer einzelnen Zeile besteht, allerdings ist es guter Stil, die geschweiften Klammern in jedem Fall zu verwenden.

Die einfache if-Anweisung ermöglicht zwar bereits die bedingte Ausführung von Code, allerdings erfordert eine exklusive Ausführung zweier Codeabschnitte zwei Abfragen, die einander außer in der Prüfung auf true oder false gleichen.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
using System;

namespace GoloRoden.GuideToCSharp
{
    /// <summary>
    /// Represents the application class.
    /// </summary>
    public class Program
    {
        /// <summary>
        /// Executes the application.
        /// </summary>
        public static void Main()
        {
            // Define a condition.
            bool condition = 23 < 42;

            // Check whether the condition evaluates to
            // true. If so, run the specified code.
            if (condition == true)
            {
                // TODO gr: Do something ...
                //          2008-01-03
            }

            // Check whether the condition evaluates to
            // false. If so, run the specified code.
            if (condition == false)
            {
                // TODO gr: Do something else ...
                //          2008-01-03
            }
        }
    }
}
Daher gibt es das Schlüsselwort else, das einen weiteren Rumpf einleitet, der ausgeführt wird, wenn die bei if genannte Bedingung eben nicht zu true evaluiert wird. Die erneute Angabe einer weiteren Bedingung kann somit also entfallen.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using System;

namespace GoloRoden.GuideToCSharp
{
    /// <summary>
    /// Represents the application class.
    /// </summary>
    public class Program
    {
        /// <summary>
        /// Executes the application.
        /// </summary>
        public static void Main()
        {
            // Define a condition.
            bool condition = 23 < 42;

            // Check whether the condition evaluates to
            // true. If so, run the specified code. If not,
            // run the second block.
            if (condition == true)
            {
                // TODO gr: Do something ...
                //          2008-01-03
            }
            else
            {
                // TODO gr: Do something else ...
                //          2008-01-03
            }
        }
    }
}
Ein wichtiger Aspekt bei der Überprüfung der Bedingung ist, dass die explizite Angabe des Vergleichs mit true oder false entfallen kann, da eine logische Bedingung automatisch zu einem der beiden Literale evaluiert wird. Ein Vergleich auf false kann dabei mit Hilfe des Operators ! durchgeführt werden.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
using System;

namespace GoloRoden.GuideToCSharp
{
    /// <summary>
    /// Represents the application class.
    /// </summary>
    public class Program
    {
        /// <summary>
        /// Executes the application.
        /// </summary>
        public static void Main()
        {
            // Define a condition.
            bool condition = 23 < 42;

            // Check whether the condition evaluates to
            // true.
            if (condition)
            {
                // TODO gr: Do something ...
                //          2008-01-03
            }

            // Check whether the condition evaluates to
            // false.
            if (!condition)
            {
                // TODO gr: Do something ...
                //          2008-01-03
            }
        }
    }
}
Unter Umständen kann es notwendig sein, mehr als zwei Optionen zu prüfen. Dazu kann auf mehrere if-Anweisungen zurückgegriffen werden, die ineinander verschachtelt werden.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
using System;

namespace GoloRoden.GuideToCSharp
{
    /// <summary>
    /// Represents the application class.
    /// </summary>
    public class Program
    {
        /// <summary>
        /// Executes the application.
        /// </summary>
        public static void Main()
        {
            // Define some conditions.
            bool condition1 = 23 < 42;
            bool condition2 = 17 < 23;

            // Check whether the first condition evaluates
            // to true.
            if (condition1)
            {
                // TODO gr: Do something ...
                //          2008-01-03
            }
            else
            {
                // Check whether the second condition
                // evaluates to true.
                if (condition2)
                {
                    // TODO gr: Do something else ...
                    //          2008-01-03
                }
                else
                {
                    // TODO gr: Do something completely
                    //          else ...
                    //          2008-01-03
                }
            }
        }
    }
}
Zunächst wird also geprüft, ob die erste Bedingung zutrifft, wenn nein, wird in den entsprechenden else-Block verzweigt, in dem wiederum die zweite Bedingung geprüft wird, und so weiter. Der innerste else-Block wird dabei nur ausgeführt, wenn alle vorangegangenen Bedingungen fehlgeschlagen sind.

Obwohl dieses Vorgehen zum gewünschten Ziel führt, wird die Darstellung bei einer zunehmenden Anzahl von Ebenen unübersichtlich. Daher gibt es die Möglichkeit, weitere Abfragen mit dem Konstrukt else if auf der gleichen Ebene wie das erste if zu positionieren. Die Angabe des abschließenden else ohne Bedingung ist dabei wiederum optional.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
using System;

namespace GoloRoden.GuideToCSharp
{
    /// <summary>
    /// Represents the application class.
    /// </summary>
    public class Program
    {
        /// <summary>
        /// Executes the application.
        /// </summary>
        public static void Main()
        {
            // Define some conditions.
            bool condition1 = 23 < 42;
            bool condition2 = 17 < 23;

            if (condition1)
            {
                // TODO gr: Do something ...
                //          2008-01-03
            }
            else if (condition2)
            {
                // TODO gr: Do something else ...
                //          2008-01-03
            }
            else
            {
                // TODO gr: Do something completely else ...
                //          2008-01-03
            }
        }
    }
}
Werden innerhalb einer Bedingung mehrere Bedingungen angegeben und mit Hilfe von logischen Operatoren wie && oder || verknüpft, werden diese in C# von links nach rechts ausgewertet. Zu beachten ist hierbei, dass C# die Auswertung abbricht, sobald das endgültige Ergebnis des Gesamtausdrucks feststeht. Diese Technik wird als Kurzschlussevaluierung bezeichnet.

Werden beispielsweise zwei Bedingungen mit Hilfe von && verknüpft und ergibt bereits die erste Bedingung false, so wird die zweite Bedingung nicht mehr ausgewertet, da der Gesamtausdruck unabhängig von deren Ergebnis in jedem Fall nur noch zu false evaluiert werden kann.

Da es häufig Abfragen der Art gibt, dass einer Variablen entweder ein oder ein anderer Wert zugewiesen werden soll, gibt es dafür in C# zwei abkürzende Schreibweisen. Handelt es sich bei der entsprechenden Variablen um eine Variable des Typs bool, so ist es kürzer, an Stelle von
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
using System;

namespace GoloRoden.GuideToCSharp
{
    /// <summary>
    /// Represents the application class.
    /// </summary>
    public class Program
    {
        /// <summary>
        /// Executes the application.
        /// </summary>
        public static void Main()
        {
            // Define a condition.
            bool condition = 23 < 42;

            // Set result to true if the condition evaluates
            // to true, otherwise set the result to false.
            bool result;
            if (condition)
            {
                result = true;
            }
            else
            {
                result = false;
            }
        }
    }
}
den verkürzten Ausdruck
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;

namespace GoloRoden.GuideToCSharp
{
    /// <summary>
    /// Represents the application class.
    /// </summary>
    public class Program
    {
        /// <summary>
        /// Executes the application.
        /// </summary>
        public static void Main()
        {
            // Define a condition.
            bool condition = 23 < 42;

            // Set the result to true if the condition
            // evaluates to true, otherwise set the result
            // to false.
            bool result = condition;
        }
    }
}
zu verwenden. Ebenso kann bei Variablen jedes beliebigen anderen Typs der einzige Operator mit drei Operanden verwendet werden, der sogenannte triäre Operator. An Stelle von
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
using System;

namespace GoloRoden.GuideToCSharp
{
    /// <summary>
    /// Represents the application class.
    /// </summary>
    public class Program
    {
        /// <summary>
        /// Executes the application.
        /// </summary>
        public static void Main()
        {
            // Define a condition.
            bool condition = 23 < 42;

            // Set the result to 23 if the condition
            // evaluates to true, otherwise set the result
            // to 42.
            int result;
            if (condition)
            {
                result = 23;
            }
            else
            {
                result = 42;
            }
        }
    }
}
lässt sich unter Zuhilfenahme des triären Operators
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;

namespace GoloRoden.GuideToCSharp
{
    /// <summary>
    /// Represents the application class.
    /// </summary>
    public class Program
    {
        /// <summary>
        /// Executes the application.
        /// </summary>
        public static void Main()
        {
            // Define a condition.
            bool condition = 23 < 42;

            // Set the result to 23 if the condition
            // evaluates to true, otherwise set the result
            // to 42.
            int result = condition ? 23 : 42;
        }
    }
}
schreiben. Des weiteren besteht im Zusammenhang mit nullbaren Wertetypen häufig der Wunsch, einen Standardwert zuzuweisen, falls der nullbare Wertetyp dem Literal null entspricht. An Stelle der umfangreichen Abfrage
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
using System;

namespace GoloRoden.GuideToCSharp
{
    /// <summary>
    /// Represents the application class.
    /// </summary>
    public class Program
    {
        /// <summary>
        /// Executes the application.
        /// </summary>
        public static void Main()
        {
            // Define a nullable type.
            int? nullableType = null;

            // Set the value type to 23 if the nullable type
            // is null, otherwise set it to the value of the
            // nullable type.
            int valueType;
            if (nullableType == null)
            {
                valueType = 23;
            }
            else
            {
                valueType = (int)nullableType;
            }
        }
    }
}
kann in C# seit der Version 2.0 der Operator ?? verwendet werden, so dass statt dessen
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;

namespace GoloRoden.GuideToCSharp
{
    /// <summary>
    /// Represents the application class.
    /// </summary>
    public class Program
    {
        /// <summary>
        /// Executes the application.
        /// </summary>
        public static void Main()
        {
            // Define a nullable type.
            int? nullableType = null;

            // Set the value type to the value of the
            // nullable type if it is not equal to null,
            // otherwise set the value type to 23.
            int valueType = nullableType ?? 23;
        }
    }
}
geschrieben werden kann. Schließlich gibt es neben if noch die Anweisung switch zur bedingten Ausführung von Code, die sich insbesondere dann anbietet, wenn für jede Ausführungsalternative der gleiche Ausdruck ausgewertet werden soll und die Ausführung nur vom jeweiligen Ergebnis abhängt.

Die switch-Anweisung erwartet die Bedingung ebenfalls innerhalb von runden Klammern, die einzelnen Fälle werden aber über entsprechende case-Zweige abgedeckt. Ebenso wie bei if gibt es auch bei switch einen optionalen Ausführungspfad ohne Bedingung, der ausgeführt wird, falls jeder vorige Option fehlschlägt, und der mit Hilfe des Schlüsselwortes default eingeleitet wird.

Alle Blöcke müssen bei switch mit dem Schlüsselwort break abgeschlossen werden.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
using System;

namespace GoloRoden.GuideToCSharp
{
    /// <summary>
    /// Represents the application class.
    /// </summary>
    public class Program
    {
        /// <summary>
        /// Executes the application.
        /// </summary>
        public static void Main()
        {
            // Set the condition.
            int condition = 23;

            // Execute code depending on the condition.
            switch (condition)
            {
                case 23:
                    // TODO gr: Do something ...
                    //          2008-01-03
                    break;
                case 42:
                    // TODO gr: Do something else ...
                    //          2008-01-03
                    break;
                default:
                    // TODO gr: Do something completely
                    //          else ...
                    //          2008-01-03
                    break;
            }
        }
    }
}
Die einzige Ausnahme davon ist das sogenannte Durchfallen von einer Alternative zu der darauffolgenden, was genutzt werden kann, falls beide Alternativen den gleichen Ausführungsblock verwenden sollen. Sobald der durchfallende Block allerdings eine einzige Zeile Code enthält, wird von C# ein entsprechender Fehler bei der Übersetzung ausgelöst.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
using System;

namespace GoloRoden.GuideToCSharp
{
    /// <summary>
    /// Represents the application class.
    /// </summary>
    public class Program
    {
        /// <summary>
        /// Executes the application.
        /// </summary>
        public static void Main()
        {
            // Define a condition.
            int condition = 23;

            // Execute code depending on the condition.
            switch (condition)
            {
                case 17:
                case 23:
                    // TODO gr: Do something ...
                    //          2008-01-03
                    break;
                case 42:
                    // TODO gr: Do something else ...
                    //          2008-01-03
                    break;
                default:
                    // TODO gr: Do something completely
                    //          else ...
                    //          2008-01-03
                    break;
            }
        }
    }
}
Prinzipiell kann in C# auch gezielt von einem Ausführungsblock in einen anderen gesprungen werden, um beispielsweise trotz enthaltenem Code in einen weiteren Ausführungsblock durchzufallen. Dies geschieht mittels des Schlüsselwortes goto. Da dies in der Praxis aber als schlechter Stil angesehen wird, wird an dieser Stelle nicht näher darauf eingegangen.

Schleifen

Während durch eine Bedingung wie if oder switch definiert werden kann, welche Anweisungen unter welchen Umständen ausgeführt werden, können Anweisungen mit Hilfe von Schleifen wiederholt ausgeführt werden, wobei die Anzahl der Wiederholungen entweder vorher festgelegt wird oder sich dynamisch während der Ausführung ergibt.

Die einfachste Schleife in C# ist eine reine Zählschleife, welche die in ihrem Rumpf enthaltenen Anweisungen in einer vorherbestimmten Anzahl an Durchläufen ausführt. Diese Schleife wird mittels des Schlüsselworts for implementiert. Innerhalb runder Klammern werden mit Hilfe dreier Ausdrücke der Initialisierungsausdruck, das Abbruchkriterium und der Aktualisierungsausdruck angegeben.

Um beispielsweise eine Anweisung n Mal auszuführen, wird zu Beginn der Schleife eine Variable mit dem Wert 0 initialisiert und anschließend in jedem Durchlauf um eins erhöht, bis die Schleife n Mal durchlaufen wurde. Diese Variable wird auch als Schleifenvariable oder Schleifeninvariante bezeichnet und enthält in jedem Durchlauf den Wert des jeweils aktuellen Durchlaufs.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using System;

namespace GoloRoden.GuideToCSharp
{
    /// <summary>
    /// Represents the application class.
    /// </summary>
    public class Program
    {
        /// <summary>
        /// Executes the application.
        /// </summary>
        public static void Main()
        {
            // Set the upper limit for the loop.
            int n = 23;

            // Initialize the invariant with 0 and execute
            // the loop as long as i is less than n.
            for (int i = 0; i < n; i++)
            {
                // Print the square numbers to the console.
                Console.WriteLine("The square number of " +
                    i + " is " + i * i + ".");
            }
        }
    }
}
Es hat sich in der Praxis eingebürgert, die Invariante mit i zu bezeichnen, obwohl dies den Namenskonventionen für lokale Variablen widerspricht. Sofern Schleifen verschachtelt werden, werden für die Invarianten der inneren Schleifen fortlaufend die Buchstaben ab j verwendet.

Des weiteren ist es guter Stil, die Invariante einer Schleife mit dem Wert 0 und nicht mit 1 zu initialisieren, wobei abhängig vom Kontext auch vollständig andere Startwerte sinnvoll sein können. Ebenso wird die Invariante in den meisten Fällen bei jedem Durchlauf um eins erhöht, jedoch kann auch dies je nach Bedarf beliebig gewählt werden. Unter Umständen sind auch Schleifen denkbar, deren Initialisierungsausdruck die Invariante zunächst auf einen hohen Wert setzt, der dann in jedem Schleifendurchlauf verringert wird - kurz, der Fantasie sind dabei keine Grenzen gesetzt.

Da das Abbruchkriterium vor jedem neuen Durchlauf überprüft wird, kann es vorkommen, dass eine for-Schleife überhaupt nicht ausgeführt wird. Dann nämlich, wenn der Initialisierungsausdruck die Invariante auf einen Wert setzt, für den das Abbruchkriterium zu false evaluiert wird.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using System;

namespace GoloRoden.GuideToCSharp
{
    /// <summary>
    /// Represents the application class.
    /// </summary>
    public class Program
    {
        /// <summary>
        /// Executes the application.
        /// </summary>
        public static void Main()
        {
            for (int i = 0; i > 1; i++)
            {
                // This loop is never executed, since i is
                // initialized with 0, so i > 1 evaluates
                // to false.
            }
        }
    }
}
Der wesentliche Nachteil der for-Schleife ist, dass von vornherein feststehen muss, wie viele Durchläufe ausgeführt werden sollen. Falls dies nicht bekannt ist, sondern nur ein Abbruchkriterium feststeht, kann in C# die while-Schleife eingesetzt werden. Ihr Prinzip entspricht dem der for-Schleife, wobei sich die Angabe innerhalb der runden Klammern auf das Abbruchkriterium beschränken.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
using System;

namespace GoloRoden.GuideToCSharp
{
    /// <summary>
    /// Represents the application class.
    /// </summary>
    public class Program
    {
        /// <summary>
        /// Executes the application.
        /// </summary>
        public static void Main()
        {
            // Set the upper limit.
            int upperLimit = 23;

            // Iterate over all square numbers from 0 to the
            // upper limit.
            int i = 0;
            while (i < upperLimit)
            {
                // Print the square number to the console.
                Console.WriteLine("The square number of " +
                    i + " is " + i * i + ".");

                // Increase i by 1.
                i++;
            }
        }
    }
}
Falls sich in einem Durchlauf nichts an der Gültigkeit des Abbruchkriteriums ändert, wird die Schleife ein weiteres Mal durchlaufen. Um keine Endlosschleife zu erhalten, ist es allerdings wichtig, darauf zu achten, dass sich das Abbruchkriterium zumindest überhaupt ändern könnte.

Wie bei der for-Schleife wird auch die while-Schleife unter Umständen kein einziges Mal durchlaufen, falls nämlich das Abbruchkriterium von vornherein zu false evaluiert wird. Daher werden diese beiden Schleifen auch als abweisende Schleifen bezeichnet.

Sofern eine Schleife in jedem Fall mindestens ein Mal durchlaufen werden soll, gibt es in C# auch eine nichtabweisende Variante der while-Schleife, die sich des Schlüsselworts do bedient.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using System;

namespace GoloRoden.GuideToCSharp
{
    /// <summary>
    /// Represents the application class.
    /// </summary>
    public class Program
    {
        /// <summary>
        /// Executes the application.
        /// </summary>
        public static void Main()
        {
            // Set the upper limit.
            int upperLimit = 23;

            // Iterate over all square numbers from 0 to the
            // upper limit.
            int i = 0;
            do
            {
                // Print the square number to the console.
                Console.WriteLine("The square number of " +
                    i + " is " + i * i + ".");

                // Increase i by 1.
                i++;
            }
            while (i < upperLimit);
        }
    }
}
Abgesehen davon, dass die do-Schleife das Abbruchkriterium erst nach und nicht vor dem Durchlauf überprüft, ist sie in ihrer sonstigen Arbeitsweise identisch mit der while-Schleife.

Beachtenswert bei diesen beiden Schleifen ist, dass der öffnenden Anweisung nie ein Semikolon folgt, das schließende while bei der do-Schleife allerdings durch ein Semikolon abgeschlossen wird.

Sprunganweisungen

In manchen Fällen kann es je nach Kontext notwendig sein, die Ausführung einer Schleife mit sofortiger Wirkung abzubrechen. Dies ist in C# mit Hilfe des Schlüsselworts break möglich, das bereits bei den einzelnen Zweigen einer switch-Anweisung Verwendung fand.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
using System;

namespace GoloRoden.GuideToCSharp
{
    /// <summary>
    /// Represents the application class.
    /// </summary>
    public class Program
    {
        /// <summary>
        /// Executes the application.
        /// </summary>
        public static void Main()
        {
            // Set the upper limit.
            int upperLimit = 23;

            // Iterate over all square numbers from 0 to the
            // upper limit.
            for (int i = 0; i < upperLimit; i++)
            {
                // Print the square number to the console.
                Console.WriteLine("The square number of " +
                    i + " is " + i * i + ".");

                // Check whether the loop shall still be continued.
                // If not, break.
                if (i > 17)
                {
                    break;
                }
            }
        }
    }
}
break bricht die Ausführung der aktuellen Schleife ab, indem es diese verlässt und in die umgebende Struktur springt. Sofern dies beispielsweise bei geschachtelten Schleifen wiederum eine Schleife ist, wird diese allerdings nach wie vor ausgeführt, da break nur eine einzelne Ebene verlässt.

Während break einen Schleifenablauf vollständig abbricht, kann es unter Umständen nur gewünscht sein, den aktuellen Durchlauf abzubrechen, prinzipiell aber innerhalb der Schleifenausführung zu bleiben, das heißt, direkt mit dem nächsten Durchlauf fortzufahren. Dies geschieht in C# mit Hilfe des Schlüsselwortes continue.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
using System;

namespace GoloRoden.GuideToCSharp
{
    /// <summary>
    /// Represents the application class.
    /// </summary>
    public class Program
    {
        /// <summary>
        /// Executes the application.
        /// </summary>
        public static void Main()
        {
            // Set the upper limit.
            int upperLimit = 23;

            // Iterate over all square numbers from 0 to the
            // upper limit.
            for (int i = 0; i < upperLimit; i++)
            {
                // Check whether the current number is odd.
                // If so, skip the current iteration.
                if (i % 2 != 0)
                {
                    continue;
                }

                // Print the square number to the console.
                Console.WriteLine("The square number of " +
                    i + " is " + i * i + ".");
            }
        }
    }
}

foreach

Zu guter letzt gibt es in C# noch eine weitere Schleife, die allerdings über kein entsprechendes Pendant in MSIL verfügt, sondern die lediglich als komfortable Lösung in C# enthalten ist, vom Compiler während der Übersetzung aber in eine klassische while-Schleife umgewandelt wird.

Diese Schleife dient dazu, alle Elemente einer Aufzählung zu durchlaufen, ohne den Aufwand, zunächst die Länge dieser Auflistung ermitteln und eine Schleifeninvariante erzeugen zu müssen. Implementiert wird diese Schleife mit Hilfe des Schlüsselwortes foreach.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
using System;

namespace GoloRoden.GuideToCSharp
{
    /// <summary>
    /// Represents the application class.
    /// </summary>
    public class Program
    {
        /// <summary>
        /// Executes the application.
        /// </summary>
        public static void Main()
        {
            // Define an array of colors.
            string[] colors =
                new string[] { "Red", "Green", "Blue" };

            // Iterate over all colors.
            foreach (string color in colors)
            {
                // Print the current color to the console.
                Console.WriteLine(color);
            }
        }
    }
}
Intern wandelt der Compiler diese Schleife in eine while-Schleife um, die mit sämtlichen Aufzählungen arbeiten kann, welche die Schnittstelle IEnumerator implementieren. Dies sind nicht nur sämtliche Arrays, sondern auch etliche der in den Namensräumen System.Collections und System.Collections.Generic enthaltenen Typen.

Im Gegensatz zu den anderen Schleifen, bei denen die Invariante als Index für eine Aufzählung dienen kann, liefert die Invariante der foreach-Schleife direkt ein Element der Aufzählung. Dabei wird allerdings nicht garantiert, in welcher Reihenfolge diese Elemente zurückgegeben werden. Insbesondere wird also nicht garantiert, dass zwei foreach-Schleifen über eine gemeinsame Aufzählung die darin enthaltenen Elemente in der identischen Reihenfolge durchlaufen.

Gelegentlich steht die Aufzählung, über die mit einer foreach-Schleife iteriert werden soll, nicht fest, sondern soll erst zur Laufzeit von einer Methode erzeugt werden. Seit C# 2.0 gibt es dafür das Schlüsselwort yield, das genau diese Funktionalität ermöglicht.

Damit eine Methode als Aufzählung für eine foreach-Schleife dienen kann, muss sie über die Schnittstelle IEnumerable als Rückgabetyp verfügen. Allerdings gibt sie nicht die gesamte Aufzählung auf einmal zurück, sondern liefert bei jedem Methodenaufruf den nächsten Wert der Aufzählung.

Das Schlüsselwort yield bewirkt, dass der nächste Aufruf die Methode an der Stelle fortsetzt, an der sie im vorherigen Durchlauf verlassen wurde. yield ermöglicht also eine zeitweise Unterbrechung der Methodenausführung.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
using System;
using System.Collections;

namespace GoloRoden.GuideToCSharp
{
    /// <summary>
    /// Represents the application class.
    /// </summary>
    public class Program
    {
        /// <summary>
        /// Executes the application.
        /// </summary>
        public static void Main()
        {
            // Iterate over all square numbers.
            foreach (int i in this.GetNextSquareNumber())
            {
                // Print the square number to the console.
                Console.WriteLine(
                    "The next square number is " + i + ".");
            }
        }

        /// <summary>
        /// Gets the next square number.
        /// </summary>
        /// <returns>The next square number.</returns>
        private IEnumerable GetNextSquareNumber()
        {
            // Initialize the square numbers with 0.
            int i = 0;

            // Iterate endlessly over all numbers.
            while (true)
            {
                // Return the current square number to the
                // caller.
                yield return i * i;

                // Increase i by 1.
                i++;
            }
        }
    }
}