Whetstone.
C# for a TypeScript developerCollections and iteration
Module 1 · Lesson 312 min

Collections and iteration

C# collections are the same shapes you know from JS, with explicit types and interface-first return types. Learn the three you’ll touch most and the rest follow.

The three collections, JS on the right in your head
var numbers = new List<int> { 1, 2, 3 };                   // a JS array
var byKey = new Dictionary<string, int> { ["a"] = 1 };      // a JS Map
var unique = new HashSet<string> { "a", "b" };              // a JS Set

numbers.Add(4);                 // numbers.push(4)
byKey["b"] = 2;                 // byKey.set("b", 2)
bool has = unique.Contains("a");// unique.has("a")

The difference from JS is that the element type is part of the type: List<int> is a list of ints and nothing else can go in. That <T> is a generic type parameter, the same idea as TS Array<T> or Map<K, V>, and it’s enforced by the compiler.

Iteration is foreach, which is for...of.

Looping
foreach (var n in numbers)          // for (const n of numbers)
{
    Console.WriteLine(n);
}

foreach (var (key, value) in byKey) // destructuring a Map's entries
{
    Console.WriteLine($"{key}={value}");
}

Now the Fusion habit that surprises TS developers: methods usually return the interface, not the concrete collection. You’ll see IReadOnlyList<T>, IReadOnlySet<T>, and IEnumerable<T> on return types far more than List<T>.

Return the read contract, not the mutable type (real DecisionQueryStore)
public async Task<IReadOnlySet<string>> GetDecidedFlightIdentities()
{
    var keys = await _dbContext.FlightDisruptionCostCalcs
        .Select(x => x.EjdpUniqueFlightKey)
        .ToListAsync();
    return keys.ToHashSet(StringComparer.OrdinalIgnoreCase);
}

The method builds a HashSet internally but returns IReadOnlySet<string>. The caller can enumerate it and check membership, but can’t add or remove, so the store’s data can’t be mutated from outside. This is “program to the interface”: expose the smallest contract that does the job.

Practice

Try it yourself

Recall

The collection dictionary

Map the three you'll use daily.

What are the C# equivalents of a JS array, a Map, and a Set, and what does IReadOnlyList<T> signal on a return type?

Reveal answer

List<T> is a JS array, Dictionary<TKey, TValue> is a Map, and HashSet<T> is a Set. IReadOnlyList<T> on a return type signals the caller gets a list they should not mutate; it's the interface (the contract) rather than the concrete List<T>, so the method promises read-only access. Returning the interface is a common Fusion habit.

Quiz

Why return the interface

A query store method returns IReadOnlySet<string> instead of HashSet<string>. Why?

  1. AIt exposes only the read contract, so callers can't mutate the returned set
  2. BThe two are completely unrelated, incompatible types
  3. CA HashSet simply can't be returned from a method
  4. DIt's slower at runtime but the C# compiler requires it
Show answer

Correct answer: A — It exposes only the read contract, so callers can't mutate the returned set

Returning IReadOnlySet<string> hands back the read-only interface, not the mutable concrete type. The caller can enumerate and check membership but can't add or remove, so the store's data can't be changed behind its back. Programming to the interface is a Fusion default you'll see on nearly every collection return.

Sign in to track your progress →