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
-
foreachis mainly used to read collection elements. -
Adding or removing items from
List<T>during enumeration invalidates its enumerator. -
Use
RemoveAll()or a reverseforloop 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 switchevaluates the marks. -
>= 90matches marks of 90 or above. -
>= 50matches 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
|
|
|
|---|---|
|
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
-
returnends the current method. -
yield returnsuspends execution and preserves iterator state. -
yield returnsupports lazy evaluation. -
Iterator methods commonly return
IEnumerable<T>orIEnumerator<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 returnproduces1. -
When
i = 2, it produces2. -
When
i = 3, it produces3. -
When
i = 4,yield breakterminates the iterator. -
Therefore,
4and5are 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 returnproduces a value without completing the iterator. -
yield breakstops the iterator completely. -
Both are used in iterator methods.
-
yield breakis useful for stopping iteration based on a condition. -
After
yield break, no more values are produced.
Quick Interview Revision
|
Concept |
Remember |
|---|---|
|
Modify collection in |
Avoid adding/removing from |
|
Switch expression |
Shorter way to select a value |
|
Pattern matching |
Check type, value, or structure |
|
|
Exit method |
|
|
Produce next element and suspend |
|
|
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#.