Iterators and Foreach
An iterator provides a standardized way to traverse a collection without exposing its internal implementation. C# includes built-in support through the IEnumerable and IEnumerator interfaces, along with the foreach loop which acts as syntactic sugar. When the compiler encounters a foreach statement, it generates code that calls GetEnumerator(), MoveNext(), and the Current property—exactly the same pattern you would write manually.
// Foreach on an array (implements IEnumerable)
int[] numbers = { 10, 20, 30 };
foreach (var n in numbers)
{
Console.WriteLine(n);
}
Creating Iterators with yield
The yield keyword allows you to build a iterator block quickly, either in a method, property, or operator. Using yield return returns one element at a time, while yield break stops the iteration early. This approach removes the need to handcraft a full IEnumerator implementation.
public static IEnumerable<string> GenerateNames()
{
yield return "Alice";
yield return "Bob";
yield return "Charlie";
yield break; // Subsequent elements are ignored
yield return "Diana";
yield return "Evan";
}
// A class that exposes its own collection through an iterator
public class SeasonCollection : IEnumerable
{
string[] seasons = { "Spring", "Summer", "Autumn", "Winter" };
public IEnumerator GetEnumerator()
{
for (int i = 0; i < seasons.Length; i++)
yield return seasons[i];
}
}
Usage:
foreach (var name in GenerateNames())
Console.WriteLine(name);
SeasonCollection sc = new SeasonCollection();
foreach (var s in sc)
Console.WriteLine(s);
Splitting Classes with partial
A class definition can be split across multiple files using the partial modifier. All parts must share the same access level and namespace, and each part must include partial. This is useful when multiple developers work on the same class or when auto‑generated code must be combined with user‑written code.
namespace MathTools
{
// First part: factorial calculation (recursive version)
public partial class Calculator
{
public long Factorial(int n)
{
if (n <= 1) return 1;
return n * Factorial(n - 1);
}
}
// Second part: power calculation (iterative)
public partial class Calculator
{
public long Power(int baseValue, int exponent)
{
long result = 1;
while (exponent-- > 0)
result *= baseValue;
return result;
}
}
}
var calc = new Calculator();
Console.WriteLine($"5! = {calc.Factorial(5)}");
Console.WriteLine($"2^10 = {calc.Power(2, 10)}");
Indexers: Array-Like Access
An indexer enables instances of a class or struct to be indexed like arrays. It is declared with the this keyword and can take one or more parameters. Indexers resemble properties but accept arguments. They can be virtual, abstract, or included in interfaces.
Simple Array Wrapper
public class BoundedArray
{
private int[] storage = new int[12];
public int this[int index]
{
get
{
if (index < 0 || index >= 12) return -1;
return storage[index];
}
set
{
if (index >= 0 && index < 12)
storage[index] = value;
}
}
}
Lookup Indexer (String to Value)
public class HexColorLookup
{
private readonly Dictionary<string, int> map = new()
{
["red"] = 0xFF0000,
["green"] = 0x00FF00,
["blue"] = 0x0000FF
};
public int this[string colorName]
{
get
{
return map.TryGetValue(colorName, out int code) ? code : -1;
}
}
}
var array = new BoundedArray();
array[0] = 100;
array[5] = 200;
Console.WriteLine(array[0]); // 100
Console.WriteLine(array[20]); // -1 (invalid)
var colors = new HexColorLookup();
Console.WriteLine(colors["blue"]); // 255 (0x0000FF)
Indexer in an Interface
Interfaces can declare indexers. The implementation class must supply the getter and setter logic. The interface itself does not include access modifiers.
public interface IDataStore
{
int this[int idx] { get; set; }
}
public class IntListWrapper : IDataStore
{
private List<int> items = new List<int>(new int[10]);
public int this[int idx]
{
get => idx >= 0 && idx < items.Count ? items[idx] : -1;
set
{
if (idx >= 0 && idx < items.Count)
items[idx] = value;
}
}
}
Example: User Status Indexer
A real‑world application of an indexer is a class that maps status strings to numeric identifiers.
public class UserStatusMap
{
string[] statuses = { "Active", "Away", "Busy", "Invisible" };
public int this[string description]
{
get
{
for (int i = 0; i < statuses.Length; i++)
if (statuses[i] == description) return i;
return -1;
}
}
}
// Usage
var status = new UserStatusMap();
Console.WriteLine(status["Busy"]); // 2
Console.WriteLine(status["Sleeping"]); // -1