.NET Tools How-To's

List and Span Pattern Matching – Using C# 11 in Rider and ReSharper

ReSharper and Rider support for C# 11

The .NET 7 SDK arrived a few months ago, with many .NET developers looking forward to this release and the brand-new C# language features that come along with it. If you haven’t put your fingers on it yet, all you need is:

  • Download the latest .NET SDK
  • Update your global.json if you have one
  • Update the TargetFramework in your project to net7.0 (only for some features)
  • Update the LangVersion property in your project to 11.0 or preview

In this series, we will dive into the most interesting features that are coming with C# 11 and show how we updated ReSharper and Rider to support you in applying them to your codebase with ease:

This first post will walk you through list patterns and span pattern matching.

List Patterns

Since the introduction of pattern matching in C# 7, we could see continuous enhancements in C# 8, C# 9, and C# 10. It comes unsurprisingly but much appreciated, that in the .NET 7 release we got another feature – list patterns (design proposal) – that pushes C# into the functional programming direction. List patterns also work on arrays; the compiler really only needs to have a Length/Count property and index accessors to do its magic.

Central to list patterns is the [] syntax. In the most simple form [] expresses an empty list or array. Inside the brackets, you can freely use any other pattern to match individual elements. New in the lineup is the range pattern, which matches the sequence of elements (or none) and can either be discarded or captured (var pattern).

In the following example, we will apply different list patterns to recursively check if a given integer array is sorted or not:

bool IsSorted<T>(Span<T> numbers) where T : INumber<T>
{
    return numbers switch
    {
        // Empty list and single item is always sorted
        [] or [_] => true,

        // If first and second of the current range are not sorted => false
        [var first, var second, ..] when first > second => false,

        // If none of the above conditions are met, proceed with the rest
        [_, .. var rest] => IsSorted(rest),

        // Throw if numbers are null
        null => throw new ArgumentNullException(nameof(numbers))
    };
}

This example really only scratches the surface of what’s possible. You can also use relational patterns, property patterns, or even nested list patterns:

bool Examples(int[][] array)
{
    return array switch              // Array with single element (another array)
    {
        [[< 5]] => true,             // ... with single element lower 5
        [{ Length: > 8 }] => false,  // ... with length greater 8
        [[]] => true,                // ... with no elements
    };
}

ReSharper and Rider 2022.3 fully support list patterns in terms of error checking, code completion and code analysis. We are still working on code inspections to suggest the use of list patterns in existing code, as well as additional refactoring actions.

Some recent tweets by our very own Alexander Shvedov should give you an impression of what cool features will be coming:

Span Pattern Matching

The introduction of Span<T> in C# 7.2 greatly improved our ability to write high-performance and allocationless code in safe C#. With C# 11, the use of Span<char> values as a replacement for string instances is greatly simplified by allowing you to pattern-match string constants against values of Span<char> and ReadOnlySpan<char>:

bool IsSpecial(ReadOnlySpan<char> str) =>
    str switch
    {
        "namespace" => true,
        "type" or "member" => true,
        _ => false
    };

ReSharper and Rider support this new language feature and allow you to convert from SequenceEqual to the leaner form with a quick-fix. For instance, as to the following switch expression:

Converting SequenceEqual to Span Pattern Matching

Conclusion

List and Span pattern matching are a great opportunity to refactor existing code and make it more concise. Let us know if you’d like to see any particular feature we haven’t thought about yet!

Also, stay tuned for the next blog post where we will take a look at everything related to strings!

image description