2

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

 1 year ago
source link: https://blog.jetbrains.com/dotnet/2023/02/20/list-and-span-pattern-matching-using-csharp-11-in-rider-and-resharper/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

.NET Tools How-To's

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

Matthias Koch
February 20, 2023

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 blog post, we will take a look at some of the most interesting features that are coming with C# 11 and how we updated ReSharper and Rider to support you and apply them to your codebase with ease.

In this first post, we will look at 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))
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
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:

Spent nearly a week making this work… We are now able to find C# expressions accessing the same values that were pattern-matched before – this helps to push/consolidate more code into the pattern pic.twitter.com/aJC93hOUVw

— Aleksandr Shvedov (@controlflow) January 18, 2023

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
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
GIF

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!

Subscribe to Blog updates

By submitting this form, I agree to the JetBrains Privacy Policy

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK