0
0
C Sharp (C#)programming~15 mins

List patterns in C Sharp (C#) - Deep Dive

Choose your learning style9 modes available
Overview - List patterns
What is it?
List patterns in C# let you check if a list or array matches a specific shape or contains certain elements in a certain order. They allow you to write clear and concise code to test lists against patterns, like checking the first few items or the length. This helps you decide what to do based on the structure of the list without writing long loops or if statements.
Why it matters
Without list patterns, checking the shape or contents of lists requires more code and can be error-prone or hard to read. List patterns make your code simpler and easier to understand, especially when you want to handle different cases based on how a list looks. This improves code quality and reduces bugs in programs that work with collections.
Where it fits
Before learning list patterns, you should know basic C# syntax, arrays, lists, and pattern matching with simple types. After mastering list patterns, you can explore more advanced pattern matching features like property patterns, recursive patterns, and switch expressions for cleaner control flow.
Mental Model
Core Idea
List patterns let you describe the shape and contents of a list directly in code to match and extract elements easily.
Think of it like...
It's like checking if a row of colored beads matches a specific sequence, for example, if the first bead is red and the next two are blue, without looking at each bead one by one.
List pattern structure:

[ element1, element2, ..., elementN, ..rest ]

Where:
  elementX = specific value or variable to match
  ..rest = optional slice to match remaining elements

Example:
[1, 2, ..var tail] matches a list starting with 1, then 2, then any remaining elements captured as tail.
Build-Up - 7 Steps
1
FoundationBasic list pattern syntax
πŸ€”
Concept: Introduces the simplest form of list patterns to match fixed elements in order.
In C#, you can use list patterns inside a switch or an if statement to check if a list matches a sequence. For example: int[] numbers = {1, 2, 3}; switch (numbers) { case [1, 2, 3]: Console.WriteLine("Exact match 1,2,3"); break; default: Console.WriteLine("No match"); break; } This checks if the array exactly matches the sequence 1, 2, 3.
Result
Output: Exact match 1,2,3
Understanding the basic syntax shows how list patterns let you compare entire lists to a fixed sequence without loops.
2
FoundationMatching variable elements in lists
πŸ€”
Concept: Shows how to capture elements from a list into variables using list patterns.
You can use variables inside list patterns to extract values: int[] numbers = {4, 5, 6}; if (numbers is [var first, var second, var third]) { Console.WriteLine($"First: {first}, Second: {second}, Third: {third}"); } This matches any list of exactly three elements and assigns each to a variable.
Result
Output: First: 4, Second: 5, Third: 6
Knowing you can extract elements directly from a list pattern makes your code concise and readable.
3
IntermediateUsing slice patterns for remaining elements
πŸ€”Before reading on: do you think list patterns can match only fixed-length lists or also lists with extra elements? Commit to your answer.
Concept: Introduces the slice pattern '..' to match any number of remaining elements in a list.
Slice patterns let you match the start of a list and capture the rest: int[] numbers = {1, 2, 3, 4, 5}; if (numbers is [1, 2, ..var rest]) { Console.WriteLine($"Rest elements count: {rest.Length}"); } This matches lists starting with 1 and 2, then captures the rest as an array.
Result
Output: Rest elements count: 3
Understanding slice patterns lets you handle lists of varying lengths while still matching specific starting elements.
4
IntermediateCombining list patterns with other patterns
πŸ€”Before reading on: can list patterns be combined with conditions on elements, like checking if a number is even? Commit to your answer.
Concept: Shows how to combine list patterns with property or relational patterns for more precise matching.
You can add conditions inside list patterns: int[] numbers = {2, 4, 6}; if (numbers is [var first and > 0, var second and > 0, ..]) { Console.WriteLine("List starts with positive numbers"); } This matches lists starting with positive numbers, regardless of length.
Result
Output: List starts with positive numbers
Knowing how to combine patterns increases the power and flexibility of list matching.
5
IntermediateUsing list patterns in switch expressions
πŸ€”
Concept: Demonstrates how list patterns simplify switch expressions for lists.
Switch expressions let you return values based on list patterns: string DescribeList(int[] numbers) => numbers switch { [] => "Empty list", [var single] => $"Single element: {single}", [1, 2, ..] => "Starts with 1, 2", _ => "Other list" }; Console.WriteLine(DescribeList(new int[] {1, 2, 3})); Console.WriteLine(DescribeList(new int[] {5}));
Result
Output: Starts with 1, 2 Single element: 5
Using list patterns in switch expressions makes code that handles many list shapes clean and expressive.
6
AdvancedPerformance considerations of list patterns
πŸ€”Before reading on: do you think list patterns always create new arrays or copies when matching? Commit to your answer.
Concept: Explains how list patterns work efficiently without unnecessary copying and their impact on performance.
List patterns use references to the original list or array and do not copy elements. Matching is done by checking elements in place. However, complex patterns or large slices may have some overhead. Understanding this helps write performant code when matching large collections.
Result
No output but improved understanding of performance tradeoffs.
Knowing the internal efficiency prevents misconceptions that list patterns are slow or heavy on memory.
7
ExpertLimitations and edge cases of list patterns
πŸ€”Before reading on: can list patterns match lists with null elements or null lists themselves? Commit to your answer.
Concept: Discusses tricky cases like null lists, empty slices, and how list patterns behave with different collection types.
List patterns require the list or array to be non-null; otherwise, matching fails. Null elements inside lists are matched normally. Also, list patterns work only on types that support indexing and length, like arrays or List. Custom collections need special support. Understanding these limits helps avoid runtime errors.
Result
No output but awareness of edge cases.
Recognizing these boundaries helps write robust code and avoid subtle bugs in production.
Under the Hood
At runtime, list patterns check the target object for length and indexer support. The pattern matcher accesses elements by index and compares them to pattern elements or extracts them into variables. Slice patterns create a new span or array segment referencing the remaining elements without copying. The matching process short-circuits on failure to improve speed.
Why designed this way?
List patterns were designed to integrate seamlessly with existing pattern matching in C# 8 and later, providing a natural syntax for common list checks. The design balances expressiveness with performance by avoiding unnecessary copies and leveraging existing interfaces like IReadOnlyList. Alternatives like manual loops were more verbose and error-prone.
Matching process flow:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Input list β”‚
β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
      β”‚
      β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Check lengthβ”‚
β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
      β”‚
      β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ For each    β”‚
β”‚ pattern elemβ”‚
β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
      β”‚
      β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Compare or  β”‚
β”‚ extract val β”‚
β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
      β”‚
      β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Slice rest  β”‚
β”‚ if present  β”‚
β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
      β”‚
      β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Match resultβ”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Myth Busters - 4 Common Misconceptions
Quick: Do list patterns create copies of the list elements when matching? Commit to yes or no.
Common Belief:List patterns always copy the matched elements into new arrays or lists.
Tap to reveal reality
Reality:List patterns do not copy elements; they reference the original list or array to avoid overhead.
Why it matters:Believing copies happen can lead to unnecessary performance worries or incorrect assumptions about side effects.
Quick: Can list patterns match null lists without error? Commit to yes or no.
Common Belief:List patterns can safely match null lists and treat them as empty or no match.
Tap to reveal reality
Reality:Matching a null list with a list pattern causes the match to fail; it does not treat null as empty.
Why it matters:Assuming null is handled silently can cause unexpected null reference exceptions or logic errors.
Quick: Do list patterns work on any collection type like LinkedList? Commit to yes or no.
Common Belief:List patterns work on all collection types, including linked lists and queues.
Tap to reveal reality
Reality:List patterns only work on types supporting indexing and length, like arrays and List. Other collections need conversion.
Why it matters:Misusing list patterns on unsupported types leads to compile errors or runtime failures.
Quick: Can list patterns be used to modify the original list elements? Commit to yes or no.
Common Belief:List patterns allow you to change elements inside the matched list directly.
Tap to reveal reality
Reality:List patterns are for matching and extracting values only; they do not modify the original list.
Why it matters:Expecting modification can cause confusion and bugs when changes do not happen.
Expert Zone
1
List patterns use the IReadOnlyList interface internally, so custom types implementing it can support list patterns without extra code.
2
When multiple list patterns are stacked or combined, the order of evaluation affects performance and matching behavior subtly.
3
Slice patterns create spans or array segments that reference the original list memory, so modifying the original list affects the slice.
When NOT to use
Avoid list patterns when working with collections that do not support indexing or have expensive index access, like LinkedList or IEnumerable. Instead, use loops or LINQ queries for those. Also, avoid list patterns for very large lists if performance profiling shows overhead.
Production Patterns
In production, list patterns are often used in parsing input sequences, command argument processing, or protocol message handling where the shape of data matters. They simplify switch expressions that handle different list shapes, improving maintainability and reducing bugs.
Connections
Pattern matching
List patterns are a specialized form of pattern matching focused on sequences.
Understanding list patterns deepens your grasp of pattern matching as a whole, showing how it applies beyond simple values to complex data structures.
Regular expressions
Both list patterns and regular expressions describe patterns to match sequences, but list patterns work on typed lists while regex works on strings.
Knowing list patterns helps appreciate how pattern matching concepts apply across different data types and domains.
Music composition
Matching list patterns is like recognizing motifs or sequences of notes in music to identify themes or variations.
This cross-domain link shows how pattern recognition is a universal skill, whether in code or art.
Common Pitfalls
#1Trying to match a null list without checking for null first.
Wrong approach:if (myList is [1, 2, 3]) { /* ... */ } // throws if myList is null
Correct approach:if (myList != null && myList is [1, 2, 3]) { /* ... */ }
Root cause:List patterns do not handle null values; forgetting to check null causes runtime errors.
#2Using list patterns on collections without indexing support.
Wrong approach:LinkedList list = new LinkedList(); if (list is [1, 2]) { /* ... */ } // compile error
Correct approach:var array = list.ToArray(); if (array is [1, 2]) { /* ... */ }
Root cause:List patterns require indexing; applying them directly to unsupported types causes errors.
#3Expecting list patterns to modify the original list elements.
Wrong approach:if (myList is [var first, ..]) { first = 10; } // does not change myList[0]
Correct approach:myList[0] = 10; // modify directly outside pattern matching
Root cause:List patterns only extract values; they do not provide references to modify the original list.
Key Takeaways
List patterns let you match and extract elements from lists or arrays using clear, concise syntax.
They support fixed-length matching and flexible matching with slice patterns for remaining elements.
List patterns work only on types with indexing and length, like arrays and List.
They do not copy elements or modify the original list; they only check and extract values.
Understanding list patterns improves your ability to write readable, maintainable code that handles collections based on their shape.