Skip to content

Collection Expressions in .Net

C# 11 introduced collection expressions (formerly known as list patterns) to .Net 7+. This little feature allows us to match lists by shape, not just by checking every position. Let us see how this can influence how we write checks.

Preparation

Given we have an integer array with the numbers 1, 2, and 3:

int[] numbers = [1, 2, 3];

When we want to check if the list matches the array [1,2,3], we need to use is and not ==:

1
2
3
4
if (numbers is [1, 2, 3])
{
    Console.WriteLine("Exact match");
}

If we would use == we would get this compiler error:

CS0019 Operator '==' cannot be applied to operands of type 'int[]' and 'collection expressions'

So far, so boring. With this little repetition on how we need to compare arrays we can now start with the collection expressions.

Match shape not the index

If we want to match any list that starts with 1, we can use the .. (the slice pattern) as a stand-in for all the parts of the list we are not interested in:

1
2
3
4
if (numbers is [1, ..])
{
    Console.WriteLine("Starts with 1");
}

This matches all lists that start with 1. If we only care about how the list ends, we can use the slice pattern first and specify the value we care about:

1
2
3
4
if (numbers is [.., 3])
{
    Console.WriteLine("Ends with 3");
}

If we care about the first and the last element, we put the slice pattern in the middle:

1
2
3
4
if (numbers is [1, .., 3])
{
    Console.WriteLine("Starts with 1 and ends with 3");
}

The slice pattern matches 0 or more elements. If we want at least one element before our list ends with 3, we can use the _ (the discard pattern) to make sure we have an element:

1
2
3
4
if (numbers is [_, .., 3])
{
    Console.WriteLine("Has at least one element before it ends with 3");
}

This matches [8,3] and [1,2,3] but not [3].

Conclusion

The collection expressions combined with the discard and slice pattern gives us a handy tool to check for specifics of a list. This gives us a lot of flexibility without the need to calculate array positions as we had to do the traditional way. Use this feature with caution, as there are always places where it can make your code harder to read.