Dynamic Array in C#: Build a Growing List Step by Step

Say you’re taking RSVPs for an Austin C# meetup on March 12, 2026, and nobody knows if 4 or 40 people will sign up. A plain array can’t help, because its size is fixed the moment you create it.

A dynamic array in C# is a List<T>: it wraps an array and swaps in a bigger one whenever it fills up. We’ll build that RSVP list with a wait list on .NET 10, one step at a time. Here’s what we’re building:

Dynamic array in C# example in VS Code: an RSVP List<string> with 4 seats for an Austin C# meetup, a wait list, Remove, Add, Sort and Contains in the dotnet run output
The finished RSVP list: four seats, a wait list and a canceled guest replaced automatically

Before You Start Building the Dynamic Array

You need the .NET 10 SDK and VS Code; every step is one file you run with dotnet run File.cs. If the square-bracket array syntax is new to you, skim my C# arrays guide first. Your sample data is one RSVP list:

AttendeeRole in the build
Jenna Morales, Marcus Reed, Olivia ChenEarly sign-ups
Tyler BrooksCancels
Dana WhitfieldSpeaker, inserted first
Ethan Parker, Hannah LeeLate sign-ups

Why Can’t a C# Array Grow? (Array.Resize Explained)

An array gets its length once, and writing past the end throws. Array.Resize is the old workaround:

string[] seats = ["Jenna Morales", "Tyler Brooks", "Marcus Reed"];
string[] before = seats;

try { seats[3] = "Olivia Chen"; }
catch (IndexOutOfRangeException ex) { Console.WriteLine(ex.Message); }

Array.Resize(ref seats, seats.Length + 1);   // new array, items copied
seats[3] = "Olivia Chen";

Console.WriteLine($"Length now: {seats.Length}");
Console.WriteLine($"Same array as before? {ReferenceEquals(seats, before)}");
Console.WriteLine($"Old array length: {before.Length}");

Output:

Index was outside the bounds of the array.
Length now: 4
Same array as before? False
Old array length: 3

It doesn’t stretch anything: it allocates a new array, copies the items and repoints your ref variable, so before still has 3 slots. Doing that on every add is slow, so I hand the job to a list.

Step 1: Create the RSVP List and Watch Count vs Capacity

Add nine sign-ups to an empty List<string>. Count is items you have; Capacity is slots in the hidden array:

List<string> rsvps = new();
Console.WriteLine($"Start: Capacity {rsvps.Capacity}");

string[] names = ["Jenna Morales", "Tyler Brooks",
    "Marcus Reed", "Olivia Chen", "Ethan Parker",
    "Hannah Lee", "Caleb Ward", "Sofia Ramirez",
    "Noah Bennett"];

foreach (string name in names)
{
    rsvps.Add(name);
    int count = rsvps.Count, cap = rsvps.Capacity;
    Console.WriteLine($"Count {count}, Capacity {cap}");
}

Output:

Start: Capacity 0
Count 1, Capacity 4
Count 2, Capacity 4
Count 3, Capacity 4
Count 4, Capacity 4
Count 5, Capacity 8
Count 6, Capacity 8
Count 7, Capacity 8
Count 8, Capacity 8
Count 9, Capacity 16
C# List Count vs Capacity in VS Code: adding nine RSVPs to an empty List<string> grows Capacity from 0 to 4, 8 and 16
Capacity jumps only when the inner array is full

In my run, Capacity went 0, 4, 8, 16. Each jump is a resize-and-copy List<T> does for you, and because it doubles, adds stay cheap on average.

Pro Tip: know the rough size? new List<string>(50) skips the early copies (more in my List in C# tutorial).

Checkpoint: the last line ends with Count 9, Capacity 16.

Step 2: Insert and Remove Attendees from the Dynamic Array

A speaker goes to the front, two people cancel and two late sign-ups arrive:

List<string> rsvps = ["Jenna Morales", "Tyler Brooks",
                      "Marcus Reed", "Olivia Chen"];

rsvps.Insert(0, "Dana Whitfield");   // speaker first
rsvps.Remove("Tyler Brooks");        // canceled, by name
rsvps.RemoveAt(rsvps.Count - 1);     // canceled, by index
rsvps.AddRange(["Ethan Parker", "Hannah Lee"]);

Console.WriteLine(string.Join(", ", rsvps));
bool removed = rsvps.Remove("Zoe Hart");
Console.WriteLine($"Remove a missing name: {removed}");
Console.WriteLine($"Count: {rsvps.Count}");

Output:

Dana Whitfield, Jenna Morales, Marcus Reed, Ethan Parker, Hannah Lee
Remove a missing name: False
Count: 5
C# dynamic array Insert, Remove, RemoveAt and AddRange on an RSVP List<string> in VS Code, with Remove returning False for a missing name
Insert shifts items right; Remove returns false when the name isn’t there

Insert shifts everyone right. Remove deletes the first match and returns false when there isn’t one; RemoveAt works by index.

Checkpoint: the first line starts with Dana Whitfield, Jenna Morales.

Step 3: Search the List with Contains, IndexOf and Find

At the door, you’ll look people up:

List<string> rsvps = ["Dana Whitfield", "Jenna Morales",
    "Marcus Reed", "Ethan Parker", "Hannah Lee"];
var noCase = StringComparer.OrdinalIgnoreCase;

Console.WriteLine(rsvps.Contains("Marcus Reed"));
Console.WriteLine(rsvps.Contains("marcus reed"));
Console.WriteLine(rsvps.Contains("marcus reed", noCase));
Console.WriteLine(rsvps.IndexOf("Ethan Parker"));
Console.WriteLine(rsvps.IndexOf("Zoe Hart"));
Console.WriteLine(rsvps.Find(n => n.StartsWith('H')));

Output:

True
False
True
3
-1
Hannah Lee
Search a C# List with Contains, IndexOf and Find in VS Code: Contains is case-sensitive, IndexOf returns -1 and Find returns null when nothing matches
Contains and IndexOf compare exact text; Find takes a condition

Contains is case-sensitive, so pass StringComparer.OrdinalIgnoreCase (the LINQ overload) for typed input. IndexOf returns -1 and Find returns null on no match.

Arrays work similarly; see how to check if a string array contains an element.

Checkpoint: the lines read True, False, True, 3, -1 and Hannah Lee.

Step 4: Loop Through and Sort the List

Print the door list A-Z, then by last name:

List<string> rsvps = ["Marcus Reed", "Dana Whitfield",
    "Jenna Morales", "Hannah Lee", "Ethan Parker"];

rsvps.Sort(StringComparer.Ordinal);   // A-Z, in place
for (int i = 0; i < rsvps.Count; i++)
    Console.WriteLine($"{i + 1}. {rsvps[i]}");

// by last name
rsvps.Sort((x, y) => string.CompareOrdinal(
    x.Split(' ')[1], y.Split(' ')[1]));
Console.Write("By last name:");
foreach (string name in rsvps)
    Console.Write($" {name.Split(' ')[1]}");
Console.WriteLine();

Output:

1. Dana Whitfield
2. Ethan Parker
3. Hannah Lee
4. Jenna Morales
5. Marcus Reed
By last name: Lee Morales Parker Reed Whitfield
Sort a C# List in VS Code: List.Sort with StringComparer.Ordinal, a numbered for loop using Count, then a Comparison lambda sorting by last name
Sort works in place; a lambda decides the order

Loop to Count, not Length. Sort changes the list itself and takes the same comparers as arrays; my guide to sort an array in C# covers descending and object sorts.

Checkpoint: the last line reads By last name: Lee Morales Parker Reed Whitfield.

Step 5: Convert the List to an Array with ToArray and [..]

The badge printer wants a fixed array, and you want guests plus the wait list in one list:

List<string> guests = ["Dana Whitfield", "Ethan Parker",
                       "Hannah Lee"];
string[] waitList = ["Caleb Ward", "Sofia Ramirez"];

string[] badges = guests.ToArray();   // fixed copy
// collection expression + spread (C# 12+)
List<string> all = [.. guests, .. waitList, "Walk-in"];

guests.Add("Noah Bennett");
Console.WriteLine($"List: {guests.Count}");
Console.WriteLine($"Array: {badges.Length}");
Console.WriteLine(string.Join(", ", all));

Output:

List: 4
Array: 3
Dana Whitfield, Ethan Parker, Hannah Lee, Caleb Ward, Sofia Ramirez, Walk-in
C# List ToArray snapshot and a collection expression with the spread element .. joining the RSVP list and the wait list in VS Code
ToArray copies; [.. a, .. b] combines

ToArray() is a copy, so adding Noah later doesn’t touch badges. The [.. guests, .. waitList] collection expression (spread element) needs C# 12 or later.

Checkpoint: List: 4 and Array: 3.

Test the Finished RSVP Dynamic Array

Here’s the program from the top. A foreach loop in C# fills four seats and wait-lists the rest; when Tyler cancels, the first wait-listed guest moves up:

const int Seats = 4;
List<string> rsvps = [], waitList = [];
string[] signups = ["Jenna Morales", "Tyler Brooks",
    "Marcus Reed", "Olivia Chen",
    "Ethan Parker", "Hannah Lee"];
foreach (string name in signups)
    (rsvps.Count < Seats ? rsvps : waitList).Add(name);
rsvps.Remove("Tyler Brooks");   // canceled
rsvps.Add(waitList[0]);         // wait list moves up
waitList.RemoveAt(0);
rsvps.Sort(StringComparer.Ordinal);

string seats = $"{rsvps.Count}/{Seats}";
Console.WriteLine($"Austin C# Meetup 3/12/2026 ({seats})");
for (int i = 0; i < rsvps.Count; i++)
    Console.WriteLine($"  {i + 1}. {rsvps[i]}");
Console.WriteLine($"Waiting: {waitList[0]}");
bool marcus = rsvps.Contains("Marcus Reed");
Console.WriteLine($"Marcus Reed seated? {marcus}");

Output:

Austin C# Meetup 3/12/2026 (4/4)
  1. Ethan Parker
  2. Jenna Morales
  3. Marcus Reed
  4. Olivia Chen
Waiting: Hannah Lee
Marcus Reed seated? True

Ethan took Tyler’s seat and Hannah’s still waiting. Two lists, and no size declared anywhere.

Array vs List<T> vs ArrayList: Which Dynamic Array Should You Use?

string[] arrayList<string>ArrayList
SizeFixedGrows and shrinksGrows and shrinks
Type-safeYesYesNo, stores object
Value typesNo boxingNo boxingBoxed
Use it forKnown size, hot loopsAlmost everythingLegacy code only

ArrayList is the pre-generics dynamic array from .NET 1.0, and Microsoft recommends List<T> for new code. I explain the migration in my ArrayList in C# tutorial.

Troubleshooting Dynamic Array Errors in C#

The two mistakes I see most:

List<string> rsvps = ["Jenna Morales", "Tyler Brooks", "Marcus Reed"];

try { Console.WriteLine(rsvps[3]); }
catch (ArgumentOutOfRangeException ex) { Console.WriteLine(ex.GetType().Name); }

try { foreach (var n in rsvps) if (n.StartsWith('T')) rsvps.Remove(n); }
catch (InvalidOperationException ex) { Console.WriteLine(ex.Message); }

rsvps.RemoveAll(n => n.StartsWith('M'));   // the safe way to remove while filtering
Console.WriteLine(string.Join(", ", rsvps));

Output:

ArgumentOutOfRangeException
Collection was modified; enumeration operation may not execute.
Jenna Morales

ArgumentOutOfRangeException: the index is >= Count. Spare Capacity isn’t readable.

Collection was modified: you can’t add or remove inside foreach. Use RemoveAll or walk a for loop in C# backwards.

Where to Take It Next

A few more array and collection tutorials you’ll find handy:

Frequently Asked Questions

Does C# have dynamic arrays?

Not as a separate type. Arrays are fixed-size; List<T> is the built-in dynamic array.

What’s the difference between Count and Capacity in a C# List?

Count is the number of items; Capacity is the size of the inner array. Microsoft’s List<T>.Capacity reference explains that the list reallocates and copies when Count exceeds Capacity.

Does Array.Resize change the original array?

No. It creates a new array and updates your ref variable; other references keep the old one.

Is List<T> slower than an array in C#?

Slightly, for reads in tight loops. When items come and go, it beats resizing an array yourself.

How do I convert a List to an array in C#?

Call list.ToArray(), or use the collection expression string[] arr = [.. list]; on C# 12 or later. Both make a copy.