Generic Lists (List<T>)
A single variable holds one value — but real programs juggle collections : a shopping cart, a list of scores, a feed of messages. is the workhorse collection of C#: an ordered, resizable container that grows as you add and shrinks as you remove. Master it and you can model almost any "many things" you'll meet.
Learn Generic Lists (List<T>) in our free C# course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick recall.
Part of the free C# course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
An array is a row of fixed, numbered parking bays — once the car park is built, you can't add a bay. A is a queue at a coffee shop : people join the back, someone leaves from the middle, the line stretches and contracts naturally, and everyone still has a clear position. That flexibility — adding and removing without rebuilding everything — is exactly why List is the default collection.
1. Creating & Reading a List
Declare a list by stating what it holds: for text, for numbers. Add items with Add , read one by its zero-based index with list[0] (or list[^1] for the last), and ask how many there are with Count . A foreach loop is the tidiest way to visit every element.
2. Modifying a List
Lists shine because they change shape. Insert places an item at a position, Remove deletes the first matching value, RemoveAt deletes by index, and Clear empties the whole thing. Contains and IndexOf answer "is it in here, and where?".
Your turn. Manage a small shopping cart — add one item, remove another, and print the result.
3. Sorting, Searching & Aggregating
Once you have a list of numbers, a whole toolbox opens up. Sort and Reverse reorder it in place; the LINQ helpers Sum , Max , Min and Average compute totals without a loop; and Find / FindAll pull out items matching a condition you express with a lambda ( n => n > 4 ).
A classic bug: removing items while iterating a list with foreach . C# detects the collection changed underneath the loop and throws InvalidOperationException . The clean fix is RemoveAll with a predicate, which does the whole job safely in one call.
If you must remove inside a loop yourself, iterate backwards with a for loop ( for (int i = list.Count - 1; i >= 0; i--) ) so removing an item doesn't shift indexes you haven't visited yet.
These six lines build a number list, drop the odd values, sort it, and print 2, 4, 6 . Put them in a working order.
Why: the list must exist before anything operates on it. Removing the odds first leaves 2, 6, 4 , then Sort orders them to 2, 4, 6 , and the WriteLine prints the final state. Sorting before removing would still work here, but removing first keeps the list smaller to sort.
20 — RemoveAt(0) drops 10 and everything shifts down, so index 0 is now 20 .
3 — after sorting, the list is 1, 2, 3 , and [^1] is the last element, 3 .
13 — Sum() adds 4 + 8 + 1 . (Requires using System.Linq; .)
Combine adding, filtering with RemoveAll , sorting, and aggregating into a small scores report. The outline is in the comments.
Practice quiz
What is the main difference between an array and a List<T> in C#?
- A List is always faster than an array
- A List grows and shrinks automatically, while an array has a fixed size
- An array can hold mixed types but a List cannot
- A List can only hold reference types
Answer: A List grows and shrinks automatically, while an array has a fixed size. An array's size is fixed at creation; a List<T> resizes automatically as you Add and Remove, which is why it is the default collection.
What does the <T> in List<T> represent?
- The total number of items
- A type parameter — the kind of element the list holds
- A threading mode
- A temporary variable
Answer: A type parameter — the kind of element the list holds. T is a type parameter you fill in when creating the list, so List<int> holds ints and List<string> holds strings, type-checked at compile time.
What does list[^1] return?
- The first element
- The element at index 1
- The last element (one from the end)
- The count of the list
Answer: The last element (one from the end). The ^1 index counts from the end, so list[^1] is the last element — cleaner than list[list.Count - 1].
What is the correct, safe way to remove every item matching a condition?
- Remove items inside a foreach over the same list
- Use RemoveAll with a predicate
- Call Clear() then re-add the keepers
- Set each matching item to null
Answer: Use RemoveAll with a predicate. RemoveAll(predicate) removes every match in one call. Removing inside a foreach over the same list throws InvalidOperationException.
What happens if you modify a List inside a foreach loop over that same list?
- It silently skips the modified item
- It throws InvalidOperationException
- It sorts the list automatically
- Nothing — it is fully supported
Answer: It throws InvalidOperationException. C# detects the collection changed underneath the loop and throws InvalidOperationException. Use RemoveAll or a backward for loop instead.
What does RemoveAt(0) do to a list of { 10, 20, 30 }?
- Removes 10, leaving { 20, 30 }
- Removes 0 items
- Removes the last item
- Removes the value 0
Answer: Removes 10, leaving { 20, 30 }. RemoveAt(0) removes the item at index 0 (the value 10); everything shifts down, so index 0 becomes 20.
Which using directive must be imported to call list.Sum(), Max(), and Average()?
- System.Text
- System.Collections.Generic
- System.Linq
- System.IO
Answer: System.Linq. Sum, Max, Min, and Average are LINQ extension methods that live in System.Linq.
What does the Sort() method do to a List<int>?
- Returns a new sorted list and leaves the original unchanged
- Sorts the list in place, mutating it
- Removes duplicates
- Reverses the list
Answer: Sorts the list in place, mutating it. Sort() mutates the list in place, reordering its elements; it does not return a new list.
What does Remove("x") do if "x" is not in the list?
- Throws an exception
- Removes the first item instead
- Returns false and changes nothing
- Adds "x" to the list
Answer: Returns false and changes nothing. Remove deletes the first matching value and returns true; if the value is absent it returns false and the list is unchanged.
Which namespace must you import to declare a List<T>?
- System.Linq
- System.Collections.Generic
- System.Text
- System
Answer: System.Collections.Generic. List<T> lives in System.Collections.Generic, so that namespace must be imported (most editors add it automatically).