← Back to Articles         
C# Collections, Switch Expressions, Pattern Matching, and Yield Keywords

C# Collections, Switch Expressions, Pattern Matching, and Yield Keywords

Published on 12 Oct 2026     5 min read C#
Control Statements & Loops

1. Can we modify a collection while iterating using foreach?

Answer: Generally, we cannot add or remove elements from a standard collection like List<T> while iterating using foreach.

Doing so invalidates the enumerator and typically throws an InvalidOperationException on the next iteration.

Simple Example

List<int> numbers = new() { 10, 20, 30, 40 };

foreach (int number in numbers)
{
    if (number == 20)
        numbers.Remove(number); // Error
}

Exception:

InvalidOperationException:
Collection was modified;
enumeration operation may not execute.

Correct Approach

Use RemoveAll() when removing elements based on a condition.

List<int> numbers = new() { 10, 20, 30, 40 };

numbers.RemoveAll(x => x == 20);

foreach (int number in numbers)
{
    Console.WriteLine(number);
}

Output:

10
30
40

Key Points

  • foreach is mainly used to read collection elements.

  • Adding or removing items from List<T> during enumeration invalidates its enumerator.

  • Use RemoveAll() or a reverse for loop for removing elements.

  • Some collections, such as ConcurrentDictionary, support concurrent modifications during enumeration with different guarantees.

 

2. What are switch expressions and pattern matching?

What is a switch expression?

A switch expression is a shorter and cleaner way to return a value based on multiple conditions.

It was introduced in C# 8.0.

Simple Example

int marks = 75;

string result = marks switch
{
    >= 90 => "Excellent",
    >= 50 => "Pass",
    _ => "Fail"
};

Console.WriteLine(result);

Output:

Pass

Explanation

  • marks switch evaluates the marks.

  • >= 90 matches marks of 90 or above.

  • >= 50 matches marks of 50 or above.

  • _ is the discard pattern, which acts like a default case.

  • => specifies the value returned for a matching pattern.

What is pattern matching?

Pattern matching checks whether a value matches a particular type, constant, range, or structure.

Example:

object value = "Hello";

if (value is string text)
{
    Console.WriteLine(text);
}

Output: Hello

Here, is string text checks the type and assigns the value to the variable text.

Key Points

  • Switch expressions provide concise conditional value selection.

  • Pattern matching supports type, relational, property, and other patterns.

  • _ acts as a catch-all pattern.

  • Switch expressions return values, whereas switch statements execute statements.

  • Both features improve code readability.

 

3. What is the difference between return and yield return?

Both return values from methods, but they behave differently.

Differences

return

yield return

Returns a value or exits a method

Produces one element at a time

Ends method execution

Suspends iterator execution

Used in normal methods

Used in iterator methods

Does not resume execution

Resumes on the next iteration

Simple Example

Using return:

static int GetNumber()
{
    return 10;
}

The method returns 10 and immediately finishes.

Using yield return:

static IEnumerable<int> GetNumbers()
{
    yield return 10;
    yield return 20;
    yield return 30;
}

foreach (int number in GetNumbers())
{
    Console.WriteLine(number);
}

Output:

10
20
30

Explanation

  • First iteration returns 10.

  • Second iteration resumes and returns 20.

  • Third iteration resumes and returns 30.

  • The iterator finishes after producing all three values.

Execution Flow

GetNumbers()
     |
     v
yield return 10 → First iteration
     |
     v
yield return 20 → Second iteration
     |
     v
yield return 30 → Third iteration
     |
     v
Iterator Completed

Key Points

  • return ends the current method.

  • yield return suspends execution and preserves iterator state.

  • yield return supports lazy evaluation.

  • Iterator methods commonly return IEnumerable<T> or IEnumerator<T>.

  • Useful when processing large sequences without materializing all elements in memory.

 

4. What is the difference between yield return and yield break?

Both keywords are used inside iterator methods.

  • yield return: Produces the next element and suspends execution.

  • yield break: Immediately terminates the iterator.

Simple Example

static IEnumerable<int> GetNumbers()
{
    for (int i = 1; i <= 5; i++)
    {
        if (i == 4)
            yield break;

        yield return i;
    }
}

foreach (int number in GetNumbers())
{
    Console.WriteLine(number);
}

Output:

1
2
3

Explanation

  • When i = 1, yield return produces 1.

  • When i = 2, it produces 2.

  • When i = 3, it produces 3.

  • When i = 4, yield break terminates the iterator.

  • Therefore, 4 and 5 are not returned.

Execution Flow

Loop starts
    |
    v
i = 1 → yield return 1
    |
    v
i = 2 → yield return 2
    |
    v
i = 3 → yield return 3
    |
    v
i = 4 → yield break
    |
    v
Iterator Stops

Key Points

  • yield return produces a value without completing the iterator.

  • yield break stops the iterator completely.

  • Both are used in iterator methods.

  • yield break is useful for stopping iteration based on a condition.

  • After yield break, no more values are produced.

 

Quick Interview Revision

Concept

Remember

Modify collection in foreach

Avoid adding/removing from List<T> during enumeration

Switch expression

Shorter way to select a value

Pattern matching

Check type, value, or structure

return

Exit method

yield return

Produce next element and suspend

yield break

Stop iterator

Interview Tip: Remember the difference between return, yield return, and yield break. These are frequently used to test your understanding of lazy execution and iterator methods in C#.

← Back to Articles