C#
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C#
-
Section 4: Working with Data
-
Section 5: Error Handling
-
Section 6: Delegates and Events
-
Section 7: Async Programming
-
Section 8: More Language Features
-
Section 9: File I/O and Serialization
-
Section 10: Networking in .NET
-
Section 11: The .NET Ecosystem
-
Section 12: Memory and Performance
-
Section 13: Concurrency Beyond Async
-
Section 14: Reflection and Attributes
-
Section 15: Testing and Best Practices
-
Section 16: Design Patterns in C#
-
Section 17: Standard Library Deep Dive
-
Section 18: Data Structures and Algorithms in C#
-
Section 19: GUI and Desktop Development Overview
-
Section 20: Practical Projects
-
Section 21: More Practice Exercises
-
Section 22: More Standard Library and Text Processing
-
Section 23: More Design Patterns
-
Section 24: More Projects
-
Section 25: Interview Practice
-
Section 26: C# Keywords Reference (Modifiers)
-
Section 27: C# Keywords Reference (Statements)
-
Section 28: C# Keywords Reference (Operators)
-
Section 29: BCL: System.Collections.Generic
-
Section 30: BCL: System.Linq
-
Section 31: BCL: System.Threading
-
Section 32: BCL: System.IO
-
Section 33: BCL: System.Text and System.Text.Json
-
Section 34: BCL: System.Net.Http
-
Section 35: C# Language Specification Topics
-
Section 36: More Practice Exercises
-
Section 37: More Async Patterns
-
Section 38: More BCL: System.Reflection and System.Diagnostics
-
Section 39: Nullable Reference Types In Depth
-
Section 40: C# Records and Pattern Matching In Depth
-
Section 41: Dependency Injection Deep Dive
-
Section 42: More Interview and Whiteboard Practice
12: For and Foreach Loops
Up until now, we've been handling data one piece at a time. But in the real world, you're almost always dealing with collections—lists of users, arrays of sensor data, or a queue of messages. That's where loops come in. Specifically, the for and foreach loops.
To show you how these actually differ in practice, let's build a simple "Daily Task Processor." We have a list of strings representing tasks, and we want to clean them up and display them.
Printing the list quickly
If all I want to do is look at every item in a list and do something with it, I don't care about the index or the "position" of the item. I just want the item itself. This is where foreach shines. It's cleaner and harder to mess up.
string[] tasks = { "Email client", "Fix bug #402", "Update docs", "Team meeting" };
foreach (string task in tasks)
{
Console.WriteLine($"Pending: {task}");
}
It reads almost like English: "for each string called task in the tasks array, do this." I use this 90% of the time because it eliminates the risk of "off-by-one" errors that haunt developers when they manage indices manually.
Running into the foreach modification wall
Now, let's say I want to be fancy. I decide that if a task contains the word "Update", it's too boring and I want to remove it from the list entirely while I'm looping through. I'll try to do this inside the foreach.
var taskList = new List<string> { "Email client", "Fix bug #402", "Update docs", "Team meeting" };
foreach (var task in taskList)
{
if (task.Contains("Update"))
{
taskList.Remove(task); // I'm thinking: "Just take it out!"
}
}
If you run this, C# is going to throw a InvalidOperationException right in your face. Why? Because foreach uses an enumerator under the hood, and C# forbids you from modifying the collection (adding or removing items) while that enumerator is active. It's a safety mechanism to prevent the loop from getting confused about where it is in the list.
Switching to a for loop for index control
To fix this, I need to switch to a standard for loop. Unlike foreach, the for loop doesn't care about the collection's state; it just cares about a number (the index).
However, there's a catch. If I remove an item at index 2, the item that was at index 3 slides down to index 2. If my loop then increments to 3, I've just skipped an item. To avoid this, I'll loop backwards. This is a common trick I use when removing items from a list.
var taskList = new List<string> { "Email client", "Fix bug #402", "Update docs", "Team meeting" };
for (int i = taskList.Count - 1; i >= 0; i--)
{
if (taskList[i].Contains("Update"))
{
Console.WriteLine($"Removing boring task: {taskList[i]}");
taskList.RemoveAt(i);
}
}
// Now let's print the final list using foreach again
foreach (var task in taskList)
{
Console.WriteLine($"Remaining: {task}");
}
Notice the difference: the for loop gives me the i variable. This allows me to access the specific slot in the array (taskList[i]) and control exactly how the counter moves. Use foreach for reading; use for when you need to manipulate the collection or need the index for logic (like "every second item").
📋 Practical Task
Build a Low-Stock Alert Filter
You are managing a warehouse inventory. You have a list of product stock levels, and you need to create a "Restock List" containing only the items that have fallen below a certain threshold.
Your requirements:
- Create an array of integers representing stock levels (e.g.,
int[] inventory = { 12, 3, 45, 2, 18, 5 };). - Create an empty
List<int>calledlowStockItems. - Use a
foreachloop to iterate through theinventory. - Inside the loop, check if the stock level is less than 10. If it is, add that number to the
lowStockItemslist. - Finally, use a
forloop to print each item in thelowStockItemslist, but include its position in the list (e.g., "Alert 1: 3 units remaining").
There are no comments for now.