Collections in C#

    Atul Kabra3 min readUpdated

    Collections in C# are classes for storing and working with groups of objects. Unlike a fixed-size array, most collections grow and shrink as your program runs. The everyday workhorses live in System.Collections.Generic: List<T> (an ordered, resizable sequence), Dictionary<TKey, TValue> (fast key-to-value lookups), and HashSet<T> (unique items, no duplicates). The <T> is a generic type parameter that makes the collection type-safe — the compiler knows exactly what it holds.

    List — an ordered, resizable sequence

    using System.Collections.Generic;
    
    List<string> students = new List<string>(); // holds strings
    students.Add("Asha");
    students.Add("Rohan");
    students.Add("Asha");                 // duplicates are allowed
    
    Console.WriteLine(students[0]);       // Asha — access by index
    Console.WriteLine(students.Count);    // 3
    students.Remove("Rohan");
    Console.WriteLine(students.Count);    // 2
    

    List<T> is what you reach for most of the time. The <string> tells the compiler the list only holds strings, so adding a number is a compile error, not a runtime surprise.

    Dictionary — key-value lookups

    A Dictionary maps unique keys to values, giving very fast lookups:

    Dictionary<string, int> marks = new Dictionary<string, int>();
    marks["Asha"] = 82;   // key "Asha" -> value 82
    marks["Rohan"] = 67;
    
    Console.WriteLine(marks["Asha"]);     // 82
    
    // Safe lookup that won't crash if the key is missing:
    if (marks.TryGetValue("Meera", out int score))
        Console.WriteLine(score);
    else
        Console.WriteLine("Not found");   // Not found
    

    Keys must be unique; assigning to an existing key replaces its value. Use TryGetValue instead of marks["Meera"] to avoid an exception when a key may not exist.

    HashSet — unique elements

    HashSet<string> tags = new HashSet<string>();
    tags.Add("dotnet");
    tags.Add("csharp");
    tags.Add("dotnet");                  // ignored — already present
    
    Console.WriteLine(tags.Count);       // 2
    Console.WriteLine(tags.Contains("csharp")); // True
    

    A HashSet automatically rejects duplicates and offers very fast membership checks.

    Iterating over a collection

    List<int> scores = new List<int> { 90, 75, 60 };
    
    // foreach reads each item in turn.
    foreach (int s in scores)
    {
        Console.WriteLine(s);
    }
    
    // Dictionaries give you key/value pairs.
    Dictionary<string, int> ages = new() { ["Asha"] = 19, ["Rohan"] = 20 };
    foreach (var pair in ages)
    {
        Console.WriteLine($"{pair.Key} is {pair.Value}");
    }
    

    Want to learn this properly?

    Join the waitlist for our courses — beginner-friendly, project-first classes in Jalgaon.

    Browse courses

    A first taste of LINQ

    LINQ lets you query collections with readable, declarative code:

    using System.Linq;
    
    List<int> nums = new List<int> { 4, 9, 2, 11, 6 };
    
    // Keep only values above 5, then sort them.
    var bigOnes = nums.Where(n => n > 5).OrderBy(n => n).ToList();
    Console.WriteLine(string.Join(", ", bigOnes)); // 6, 9, 11
    
    int total = nums.Sum();          // 32
    double average = nums.Average(); // 6.4
    

    The n => n > 5 part is a lambda — a short inline function. LINQ methods like Where, OrderBy, Sum, and Average work on almost any collection.

    Arrays vs collections

    An array has a fixed size set at creation:

    int[] fixedScores = new int[3]; // exactly 3 slots, can't grow
    fixedScores[0] = 100;
    

    Use an array when the size is known and never changes; use List<T> when it varies.

    Common mistakes

    • Indexing a missing dictionary key. dict["missing"] throws. Use TryGetValue or ContainsKey first.
    • Modifying a collection while iterating it. Adding or removing inside a foreach over the same collection throws an InvalidOperationException. Collect changes separately.
    • Forgetting using System.Collections.Generic. Without it, List and Dictionary won't resolve (though modern templates include common usings automatically).
    • Reaching for an array when a List fits. If the size changes, List<T> saves you manual resizing.

    FAQ

    When should I use a Dictionary over a List? When you look items up by a unique key (like a student ID). Dictionary lookups are far faster than scanning a list.

    Is LINQ slower? For most app code the difference is negligible and the readability gain is large. Optimize only if profiling shows a real problem.

    Keep learning

    Build data-driven apps with guidance in Jalgaon — join the waitlist for the Infoplanet .NET course at /courses/dotnet.

    Want to learn this properly?

    Join the waitlist for our courses — beginner-friendly, project-first classes in Jalgaon.

    Browse courses
    Atul Kabra

    Founder, Infoplanet

    Atul Kabra founded Infoplanet in 2001 and has spent over two decades teaching programming — C, C++, Java, databases and more — to students across Maharashtra.

    Related guides