C# 11 List Patterns
C# and Pattern Matching
With each latest iteration of C#, we see more and more pattern matching. Frankly, I'm deeply excited to see this evolution. C# of course can still be considered an Object Oriented language but MS has taken the Multi-modal moniker and then ran with it.
F# has been an incredible source of inspiration for the C# team, not to mention the Pythion influence when we left Program
in the background. So long old friend ๐ We've seen a great deal of Functionally oriented features. From first-class tuples, immutable types, and of course pattern matching!
Pattern Power ๐ช
What is a Pattern again?
Simply put, a pattern is the shape of an input that you expect to see. You declare what to expect and allow our friend Roslyn to create the ultimate boolean expression to fulfill the pattern search.
List Patterns
The latest addition to the crowd is List Patterning
We can take any sequence and describe what we'd like to switch
on from a mix of syntax cues.
Patterns are described by
- Square brackets
[]
Within the brackets, we can match
Any single element
_
with the Discard PatternMany contiguous elements
..
with the Slice Pattern
We can even mix in existing patterns to further refine our Sequence Pattern
Relational Patterns
<
,>=
, etc.Logical Patterns
and
,or
,not
And don't forget! Even with these complex List Patterns we still have a bit of a safety net to enforce fully closed pattern expressions as usual with switch {}
To Action - The basics
We have a basic Discard match
[Fact]
public void Match_Discard_Pattern()
{
var seq = new[] { 1, 2 };
var result = seq switch
{
[_, 2] => true,
_ => false
};
result.Should().BeTrue();
}
Next, we'll Slice the sequence
[Fact]
public void Match_Slice_Pattern()
{
var seq = new[] { 1, 2 };
var result = seq switch
{
[..] => true,
_ => false
};
result.Should().BeTrue();
}
We can use Relational Patterns
[Fact]
public void Match_Relational_Pattern()
{
var seq = new[] { 1, 2 };
var result = seq switch
{
[_, > 1] => true,
_ => false
};
result.Should().BeTrue();
}
We can even mix in Logical Patterns
[Fact]
public void Match_Relational_Logical_Pattern()
{
var seq = new[] { 1, 2 };
var result = seq switch
{
[_, > 1 and < 3] => true,
_ => false
};
result.Should().BeTrue();
}
Level Up Your Patterns
List Patterns are recursive and can contain any combination of nested Patterns. Combining all the available patterns, we can thoroughly inspect the content of a sequence and enforce positional relationships within the sequence. If we have a set of objects, say Person
public sealed record Person(string Name, int Age);
For us to express the idea that Josh must be second in our sequence we can write the following pattern
[Fact]
public void Match_Positional_Pattern()
{
var seq = new Person[]
{
new("Mike", 23),
new("Josh", 67)
};
var result = seq switch
{
[_, ("Josh", _)] => true,
_ => false
};
result.Should().BeTrue();
}
We can even express a Property Pattern
[Fact]
public void Match_Property_Pattern()
{
var seq = new Person[]
{
new("Mike", 23),
new("Josh", 67)
};
var result = seq switch
{
[_, { Age: > 18 }] => true,
_ => false
};
result.Should().BeTrue();
}
And don't forget we can capture sequence elements in our switch expression
[Fact]
public void Match_Var_Pattern()
{
var seq = new Person[]
{
new("Mike", 23),
new("Josh", 67)
};
var result = seq switch
{
[_, var person] => person,
_ => null
};
result.Should().BeEquivalentTo(seq[1]);
}
Imagination is the limit!
Don't stop here! These new powerful patterns are just aching to be leveraged in new and brilliant ways. The C# team keeps delivering powerful advancements to an already incredible language.
Please share your creativity in the comments, what can you do with these patterns!?
Subscribe to my newsletter
Read articles from Joshua Steward directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by