C# Collections Tutorial with Examples

⚡ Smart Summary

Collections in C# provide a flexible way to store and manage groups of objects. Unlike arrays, collections grow and shrink at runtime, and the System.Collections and System.Collections.Generic namespaces supply ready-made types for lists, dictionaries, stacks, and queues.

  • 🔃 Dynamic sizing: Collections add and remove elements at runtime, so you do not fix the size in advance like an array.
  • 📚 Namespaces: System.Collections holds the non-generic types, while System.Collections.Generic holds the type-safe generic types.
  • 🧱 Core classes: ArrayList, Stack, Queue, Hashtable, SortedList, and BitArray cover the common non-generic needs.
  • Generic power: List, Dictionary, HashSet, and Queue add compile-time type safety and better performance.
  • 🔑 Right choice: Use a Dictionary for key lookups, a List for ordered items, and a Stack or Queue for LIFO or FIFO order.
  • 🤖 AI assistance: GitHub Copilot scaffolds collection code, and ML.NET pipelines pass data through generic collection types.

Collections in C#

In our previous tutorial, we have learned about how we can use arrays in C#. Let’s have a quick overview of it, Arrays in programming are used to group a set of related objects. So one could create an array or a set of Integers, which could be accessed via one variable name.

What is Collections in C#?

Collections are similar to Arrays, it provides a more flexible way of working with a group of objects.

In arrays, you would have noticed that you need to define the number of elements in an array beforehand. This had to be done when the array was declared.

But in a collection, you don’t need to define the size of the collection beforehand. You can add elements or even remove elements from the collection at any point of time. This chapter will focus on how we can work with the different collections available in C#.

System.Collections Classes

The .NET Framework groups the original non-generic collection classes inside the System.Collections namespace. The table below summarizes the main types you can use straight away.

Collection Description
ArrayList The ArrayList collection is similar to the Arrays data type in C#. The biggest difference is the dynamic nature of the array list collection.
Stack The stack is a special case collection which represents a last in first out (LIFO) concept.
Queues The Queue is a special case collection which represents a first in first out concept.
Hashtable A hash table is a special collection that is used to store key-value items.
SortedList The SortedList is a collection which stores key-value pairs in the ascending order of key by default.
BitArray A bit array is an array of data structure which stores bits.

Generic Collections in C#

The non-generic classes above store every element as a general object, which means the compiler cannot check the type and the program pays a small cost for boxing values. To solve this, C# added the System.Collections.Generic namespace, where each collection is bound to one declared type.

A generic collection such as List<string> only accepts strings, so mistakes are caught at compile time and no casting is needed when you read an item back. This makes generic collections safer, faster, and easier to read, which is why they are the default choice in modern C# code.

The most common generic collections are listed below:

  • List<T>: A resizable, index-based list, the generic replacement for ArrayList.
  • Dictionary<TKey, TValue>: Stores key-value pairs with fast, hash-based lookups.
  • HashSet<T>: Holds only unique values and supports set operations such as union.
  • Queue<T>: A first in first out collection, the generic version of Queue.
  • Stack<T>: A last in first out collection, the generic version of Stack.
  • SortedList<TKey, TValue>: Keeps key-value pairs sorted by key in ascending order.

C# List Collection Example

The List is the most widely used generic collection because it behaves like a dynamic array. The example below creates a list of strings, adds and removes items, reads its size, and then prints the remaining values. All the code is written in the Program.cs file.

Step 1) Import the System.Collections.Generic namespace and declare a List of strings.

Step 2) Add items with the Add method and delete one with the Remove method.

Step 3) Read the Count property, then loop through the list with a foreach statement.

using System;
using System.Collections.Generic;
namespace DemoApplication
{
 class Program
 {
  static void Main(string[] args)
  {
   List<string> tutorials = new List<string>();
   tutorials.Add("Java");
   tutorials.Add("Python");
   tutorials.Add("Kotlin");
   tutorials.Remove("Python");
   Console.WriteLine(tutorials.Count);
   foreach (string tutorial in tutorials)
   {
    Console.WriteLine(tutorial);
   }
   Console.ReadKey();
  }
 }
}

Code Explanation:-

  1. The System.Collections.Generic namespace is imported so the List type is available to the program.
  2. A new List<string> called tutorials is created, and three names are added with the Add method.
  3. The Remove method deletes the value “Python”, which leaves two items in the list.
  4. The Count property returns the number of items, and the foreach loop prints each remaining value in order.

When the program runs, it first prints the count of 2, followed by Java and Kotlin on separate lines. This shows how a collection changes its size at runtime, something a fixed array cannot do.

Difference Between Arrays and Collections in C#

Both an array and a collection group related items under one name, yet they behave differently once the program is running. Knowing when to use each helps you write cleaner and more efficient code.

The main differences are listed below:

  • Size: An array has a fixed length set at declaration, while a collection can grow or shrink at any time.
  • Type handling: An array stores a single type, whereas a collection can be type-safe with generics or hold objects of mixed types when non-generic.
  • Location: Arrays are built into the language, while collection classes live in the System.Collections and System.Collections.Generic namespaces.
  • Built-in operations: Collections offer ready methods to add, remove, search, and sort items, while arrays provide only basic indexed access.
  • Best use: Choose an array when the number of items is known and fixed, and a collection when the count changes as the program runs.

In short, arrays are best for fixed-size data, while collections give the flexibility that most real-world applications need.

FAQs

Use a Dictionary when you need fast lookups by a unique key, such as an ID mapped to a record. It finds values in near constant time, while a List must scan items one by one.

HashSet and Dictionary provide the fastest lookups because they use hashing to reach an element in near constant time. A List or an array is slower because it may need to check every element in sequence.

Concurrent collections live in the System.Collections.Concurrent namespace and are built for multithreaded code. Types such as ConcurrentDictionary and BlockingCollection let several threads add and remove items safely without manual locks.

IEnumerable is the base interface that only supports reading items with a foreach loop. ICollection extends it and adds members such as Count, Add, and Remove, so it also supports modifying the collection.

List is a generic, type-safe collection that stores one declared type, giving compile-time checks and better performance. ArrayList is non-generic and stores every item as an object, which needs casting and allows mixed types.

A Stack works on a last in first out order, so the most recent item is removed first using Pop. A Queue works on a first in first out order, so the oldest item is removed first using Dequeue.

Yes. GitHub Copilot can suggest the right collection type, generate loops that add or filter items, and complete LINQ queries from a short comment, which speeds up work with lists, dictionaries, and other collections.

ML.NET feeds training data through collections such as List and IEnumerable, which map to its IDataView pipeline. Storing samples in a strongly typed generic collection keeps the machine learning workflow clear and type-safe.

Summarize this post with: