Arrays and List<T>

C# · Essentials · 10 min

Nearly every program holds data in arrays or lists; knowing their trade-offs is basic fluency.

An array has a fixed length set at creation: int[] a = new int[5]; (all zeros) or int[] b = [1, 2, 3];. Access by index from 0; out-of-range access throws IndexOutOfRangeException. a.Length gives the size. Multi-dimensional arrays exist (int[,]), as do jagged arrays (int[][]).

List<T> (in System.Collections.Generic) is the growable workhorse: Add, AddRange, Insert, Remove, RemoveAt, Contains, IndexOf, Sort, and Count for the size. Internally it wraps an array that is doubled when full, so Add is amortized O(1) while Insert(0, x) is O(n).

Collection expressions (C# 12) give one syntax for arrays, lists and spans: List<string> names = ["Ada", "Linus"];. The spread operator .. inlines another collection: [..first, ..second, 99].

Arrays and lists are reference types: assigning one to another variable copies the reference, so both see the same items. Copy explicitly with [..list], list.ToList() or array.ToArray() when you need independent data.

Indices from the end use ^: list[^1] is the last element. Ranges a[1..3] slice arrays (creating a copy) and strings.

Use an array when the size is fixed or for performance-sensitive code; use List<T> everywhere else.

Example

int[] squares = new int[4];
for (int i = 0; i < squares.Length; i++) squares[i] = i * i;
Console.WriteLine(string.Join(",", squares));   // 0,1,4,9
Console.WriteLine(string.Join(",", squares[1..3])); // 1,4

List<string> names = ["Ada", "Linus"];
names.Add("Grace");
names.Insert(0, "Alan");
names.Remove("Linus");
Console.WriteLine($"{names.Count}: {string.Join(" ", names)}"); // 3: Alan Ada Grace
Console.WriteLine(names[^1]);                   // Grace

var alias = names;          // same list
var copy = names.ToList();  // independent copy
alias.Add("Barbara");
Console.WriteLine($"{names.Count} {copy.Count}"); // 4 3

int[] merged = [..squares, 100];
Console.WriteLine(merged.Length);               // 5

Remember

  • Arrays are fixed size; List<T> grows as needed
  • Collection expressions [a, b, ..other] work for arrays and lists
  • Assignment copies the reference, not the items
  • ^1 indexes from the end, a..b slices

Watch out for

  • Expecting var b = a; to copy a list; both variables now share one list.

Check yourself

  1. var a = new List<int> {1}; var b = a; b.Add(2); What is a.Count?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/arrays