Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions docs/csharp/fundamentals/statements/iteration-statements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
---
title: "Iteration statements in C#"
description: Use foreach, while, do-while, and for to repeat a block of code, and use break and continue to control the flow of a loop.
ms.date: 07/09/2026
ms.topic: concept-article
ai-usage: ai-assisted
---

# Iteration statements

> [!TIP]
> This article is part of the **Fundamentals** section for developers who already know at least one programming language and are learning C#. If you're new to programming, start with the [Get started](../../tour-of-csharp/tutorials/index.md) tutorials first. For the complete syntax, see [iteration statements](../../language-reference/statements/iteration-statements.md) in the language reference.
>
> **Coming from another language?** All four C# loops (`foreach`, `while`, `do`-`while`, and `for`) have direct equivalents in Java, C++, and JavaScript. You use `foreach` most often. It iterates a collection without an index, like Java's enhanced `for` or JavaScript's `for...of`.

Iteration statements run a block of code repeatedly. Each pass through the block is an *iteration*, and a repeating block is a *loop*. C# provides four loops. Start with `foreach` for collections, use `while` and `do`-`while` when a condition controls the repetition, and use `for` when you need an explicit index.

## Iterate a collection with `foreach`

The `foreach` statement runs its body once for each element in a collection, in order. It's the most common choice for reading a collection because you don't manage an index or a bounds check. The `foreach` statement prevents typical off-by-one errors:

:::code language="csharp" source="./snippets/iteration-statements/Program.cs" id="Foreach":::

`foreach` works with any type that C# recognizes as a sequence, including arrays, <xref:System.Collections.Generic.List`1>, and <xref:System.Collections.Generic.Dictionary`2>. The iteration variable (`name` in the previous example) is read-only, so you can't reassign it inside the loop.

The body of a loop is a single *statement*, which is one complete instruction that C# runs, such as an assignment or a method call. A *block statement* groups zero or more statements between braces (`{ }`) and counts as a single statement itself. That's why braces are legal even around one line: the block is the statement that the loop repeats.

Enclose the loop body in braces, even for a single statement. Braces make the scope explicit and prevent a common mistake: adding a second line later that you expect to run each iteration, but that runs once after the loop instead. C# doesn't treat whitespace as significant, so indentation alone never decides which statements belong to the loop; only the braces do. Indent your code for readability, but rely on braces to define the block.

## Repeat while a condition holds with `while`

A `while` loop checks its Boolean condition *before* each iteration. If the condition is `false` at the start, the body never runs, so a `while` loop runs zero or more times:

:::code language="csharp" source="./snippets/iteration-statements/Program.cs" id="While":::

Make sure something inside the loop changes the condition. In the previous example, `countdown--` eventually makes the condition `false`. A loop whose condition never becomes `false` runs forever.

## Run the body at least once with `do`-`while`

A `do`-`while` loop checks its condition *after* each iteration, so the body always runs at least once. Use it when the first pass must happen before you can evaluate the condition, such as prompting for input and then validating it:

:::code language="csharp" source="./snippets/iteration-statements/Program.cs" id="DoWhile":::

## Count with `for`

A `for` loop statement contains three parts: an *initializer* that runs once before the loop, a *condition* that's checked before each iteration, and an *iterator* that runs after each iteration. Use `for` when you need the index itself, not just the elements:

:::code language="csharp" source="./snippets/iteration-statements/Program.cs" id="For":::

When you only need the elements and not their positions, prefer `foreach`. It states the intent more clearly and avoids index arithmetic.

## Exit or skip with `break` and `continue`

Two jump statements give you finer control inside any loop. The `break` statement exits the loop immediately, skipping any remaining iterations:

:::code language="csharp" source="./snippets/iteration-statements/Program.cs" id="Break":::

The `continue` statement skips the rest of the current iteration and moves on to the next one:

:::code language="csharp" source="./snippets/iteration-statements/Program.cs" id="Continue":::

## Iterate an asynchronous stream with `await foreach`

An *asynchronous stream* is a reader that uses an asynchronous task to produce each next element. C# represents it with the <xref:System.Collections.Generic.IAsyncEnumerable`1> interface. Data that arrives over time, such as pages from a web API or rows from a database, fits this model: retrieving the next element is an awaitable operation instead of an immediate return.

To consume an asynchronous stream, put the `await` keyword before `foreach`. Each iteration awaits the next element, so the loop suspends while that element is produced instead of blocking the thread:

:::code language="csharp" source="./snippets/iteration-statements/Program.cs" id="AwaitForeach":::

Asynchronous streams build on `async` and `await`. For a full walkthrough, see [Generate and consume asynchronous streams](../../asynchronous-programming/generate-consume-asynchronous-stream.md).

## See also

- [Selection statements](selection-statements.md)
- [Iteration statements (language reference)](../../language-reference/statements/iteration-statements.md)
- [Generate and consume asynchronous streams](../../asynchronous-programming/generate-consume-asynchronous-stream.md)
73 changes: 73 additions & 0 deletions docs/csharp/fundamentals/statements/selection-statements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
title: "Selection statements in C#"
description: Use if, else, and switch statements to choose which code runs based on a condition, including pattern-based case labels and when clauses.
ms.date: 07/09/2026
ms.topic: concept-article
ai-usage: ai-assisted
---

# Selection statements

> [!TIP]
> This article is part of the **Fundamentals** section for developers who already know at least one programming language and are learning C#. If you're new to programming, start with the [Get started](../../tour-of-csharp/tutorials/index.md) tutorials first. For the complete syntax, see [selection statements](../../language-reference/statements/selection-statements.md) in the language reference.
>
> **Coming from another language?** C++, Java, and JavaScript all share C's heritage, so `if`, `else`, and `switch` read the same in C#. The one difference worth noting: C# forbids fall-through between nonempty `switch` cases, and each `case` label can test a *pattern* rather than only a constant. If you're coming from Python, C#'s `if`/`else if`/`else` maps to `if`/`elif`/`else`, and C#'s pattern-based `switch` is closest to Python's `match` statement.

Selection statements choose which block of code runs based on a condition. C# provides two: `if` (with an optional `else`) for branching on a Boolean value, and `switch` for comparing one value against several cases. A *Boolean expression* is any expression that evaluates to `true` or `false`, such as the comparison `temperature >= 25`.

## Branch with `if` and `else`

An `if` statement runs its block only when its Boolean expression is `true`. Add an `else` block to supply the code that runs when the condition is `false`:

:::code language="csharp" source="./snippets/selection-statements/Program.cs" id="IfElse":::

The body of an `if` or `else` is a single *statement*, which is one complete instruction that C# runs, such as an assignment or a method call. A *block statement* groups zero or more statements between braces (`{ }`) and counts as a single statement itself. That's why braces are legal even around one line: the block is the statement that the branch runs.

Enclose the branch bodies in braces, even for a single statement. Braces make the scope explicit and prevent a common mistake: adding a second line later that you expect to run conditionally, but that runs unconditionally instead. C# doesn't treat whitespace as significant, so indentation alone never decides which statements belong to a branch; only the braces do. Indent your code for readability, but rely on braces to define the block.

## Test several conditions with `else if`

To choose among more than two paths, chain conditions with `else if`. C# evaluates each condition in order and runs the first block whose condition is `true`, then skips the rest. A final `else` handles every remaining case:

:::code language="csharp" source="./snippets/selection-statements/Program.cs" id="ElseIf":::

Order matters in a chain. Because the first matching condition wins, put the most specific conditions first. In the previous example, testing `score >= 80` before `score >= 70` ensures a score of 82 maps to `"B"` rather than `"C"`.

## Match a value with a `switch` statement

When you compare a single value against many discrete cases, a `switch` statement reads more clearly than a long `else if` chain. Like `if`, the `switch` statement is a branching statement: it chooses which code to run. Each `case` label lists a value to match, and each `case` section ends with a `break` statement. Stack labels to share one body, and use the `default` section for values that no case matches:

:::code language="csharp" source="./snippets/selection-statements/Program.cs" id="SwitchStatement":::

Unlike C and Java, C# doesn't allow execution to fall through from one nonempty `case` section into the next. Every section that contains code must end with a `break` (or another jump statement, such as `return` or `goto`). This rule prevents the accidental fall-through bugs common in those languages.

### Test patterns with `case` and `when`

A `case` label isn't limited to constant values. It can test a *pattern*, which is a rule that describes the shape or value of data. A relational pattern such as `< 0` matches any value less than zero. Add a `when` clause to attach an extra condition that must also be `true` for the case to match:

:::code language="csharp" source="./snippets/selection-statements/Program.cs" id="SwitchWhen":::

Pattern-based cases are evaluated top to bottom, so more specific patterns belong before more general ones. For the full catalog of patterns, see [pattern matching](../functional/pattern-matching.md).

## Select a value with an expression

The `if` and `switch` statements decide which code runs. When you instead need to choose a *value*, use an *expression*. An expression evaluates to a value, so you can use it anywhere a value is expected, such as the right side of an assignment or a method argument. C# offers expression forms that select a value from alternatives such as the conditional operator and the `switch` expression.

### Conditional operator `?:`

The conditional operator `?:` chooses between two values based on a Boolean condition. It takes the form `condition ? valueIfTrue : valueIfFalse`:

:::code language="csharp" source="./snippets/selection-statements/Program.cs" id="Ternary":::

Use `?:` when you assign one of two values, because it keeps the assignment in one place and lets you mark the variable `readonly` or `const`. Prefer an `if` statement when the branches do more than produce a value. For the operator's precedence and associativity rules, see the [conditional operator](../../language-reference/operators/conditional-operator.md) in the language reference.

### `switch` expression

A `switch` expression is the expression counterpart to the `switch` statement. Instead of running code for the matching case, it evaluates to a value. It's more concise than assigning a value in each arm of a `switch` statement, and the compiler warns you when the arms don't cover every possible input. The `switch` expression is a core part of pattern matching. To learn when and how to use it, see [pattern matching](../functional/pattern-matching.md) and the [`switch` expression](../../language-reference/operators/switch-expression.md) reference.

## See also

- [Iteration statements](iteration-statements.md)
- [Pattern matching](../functional/pattern-matching.md)
- [Selection statements (language reference)](../../language-reference/statements/selection-statements.md)
- [Conditional operator (language reference)](../../language-reference/operators/conditional-operator.md)
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
namespace IterationStatements;

public static class Program
{
public static async Task Main()
{
ForeachExample();
WhileExample();
DoWhileExample();
ForExample();
BreakExample();
ContinueExample();
await AwaitForeachExample();
}

private static void ForeachExample()
{
// <Foreach>
string[] names = ["Ana", "Ben", "Cleo"];

// foreach reads each element in order. It's the default loop for
// collections: no index to manage and no off-by-one mistakes.
foreach (string name in names)
{
Console.WriteLine(name); // => Ana, then Ben, then Cleo
}
// </Foreach>
}

private static void WhileExample()
{
// <While>
int countdown = 3;

// A while loop checks its condition before each iteration, so the body
// runs zero or more times.
while (countdown > 0)
{
Console.WriteLine(countdown); // => 3, then 2, then 1
countdown--;
}
// </While>
}

private static void DoWhileExample()
{
// <DoWhile>
int attempts = 0;

// A do-while loop runs its body once, then checks the condition. Use it
// when the body must run at least one time.
do
{
attempts++;
Console.WriteLine($"Attempt {attempts}"); // => Attempt 1, then Attempt 2, then Attempt 3
}
while (attempts < 3);
// </DoWhile>
}

private static void ForExample()
{
// <For>
// A for loop fits when you need an explicit index. The three parts are
// the initializer, the condition, and the iterator.
for (int i = 0; i < 3; i++)
{
Console.WriteLine(i); // => 0, then 1, then 2
}
// </For>
}

private static void BreakExample()
{
// <Break>
int[] numbers = [2, 4, 7, 8];

// break stops the loop immediately, skipping any remaining elements.
foreach (int number in numbers)
{
if (number % 2 != 0)
{
Console.WriteLine($"First odd number: {number}"); // => First odd number: 7
break;
}
}
// </Break>
}

private static void ContinueExample()
{
// <Continue>
int[] values = [1, 2, 3, 4, 5];

// continue skips the rest of the current iteration and moves to the next.
foreach (int value in values)
{
if (value % 2 == 0)
{
continue; // skip even numbers
}

Console.WriteLine(value); // => 1, then 3, then 5
}
// </Continue>
}

// <AwaitForeach>
private static async Task AwaitForeachExample()
{
// await foreach consumes an asynchronous stream. Each iteration can
// suspend while the next element is produced.
await foreach (int value in GenerateAsync())
{
Console.WriteLine(value); // => 0, then 1, then 2
}
}

private static async IAsyncEnumerable<int> GenerateAsync()
{
for (int i = 0; i < 3; i++)
{
await Task.Delay(1); // stand-in for real asynchronous work
yield return i;
}
}
// </AwaitForeach>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
</Project>
Loading
Loading