30 Days Of .NET 6 - Day 27 - Extended Property Patterns
[.NET, C#, 30 Days Of .NET 6]
Pattern matching is a powerful feature borrowed from functional languages that can make a whole class of problems simpler to solve.
Take for example these (somewhat convoluted) types:
public enum Speed { VeryFast, Fast, Medium, Slow }
public record Movement
{
public byte Legs { get; init; }
public byte Fins { get; init; }
public Speed Speed { get; init; }
}
public record Animal
{
public string Name { get; init; }
public Movement Movement { get; init; }
}
public record Mammal : Animal { }
public record Bird : Animal { }
We have a parent Animal
record, and two inherited records, Mammal
and Bird
.
Each has within a complex property, Movement
.
Suppose then we had a collection of Animal:
var animals = new Animal[]{
new Mammal(){ Name = "Dog", Movement = new Movement() { Legs = 4, Speed = Speed.Medium }},
new Mammal(){ Name = "Cat", Movement = new Movement() { Legs = 4, Speed = Speed.Slow }},
new Mammal(){ Name = "Dolphin", Movement = new Movement() { Fins = 2, Speed=Speed.Fast }},
new Mammal(){ Name = "Whale", Movement = new Movement() { Fins = 2, Speed=Speed.Slow }},
new Bird(){ Name = "Chicken", Movement = new Movement() { Legs = 2, Speed = Speed.Slow }},
new Bird(){ Name = "Duck", Movement = new Movement() { Legs = 2,Speed = Speed.Slow }}
};
Suppose we then wanted to filter:
- Mammals
- With no legs
- That are slow
The most obvious way is a LINQ expression:
var result = animals.Where(a => a is Mammal && a.Movement.Legs == 0 && a.Movement.Speed == Speed.Slow);
foreach (var animal in result)
Console.WriteLine($"I am a {animal.Name} and I have no legs!");
This will print, as expected,
I am a Whale and I have no legs!
Another way to do this is to use property patterns.
You can rewrite the code like this without using LINQ
foreach (var animal in animals)
{
if (animal is Mammal { Movement: { Legs: 0, Speed: Speed.Slow } })
Console.WriteLine($"I am a {animal.Name} and I have no legs!");
}
This code works in C# 9. But if you look at this bit:
It is a bit unwieldy.
This has been improved in C# 10.
You can rewrite the code like this:
foreach (var animal in animals)
{
if (animal is Mammal { Movement.Legs: 0, Movement.Speed: Speed.Slow })
Console.WriteLine($"I am a {animal.Name} and I have no legs!");
}
Note the subtle difference:
The properties now are specified as simple nested properties, without the need for nested braces.
Thoughts
This simplified syntax makes these expressions easier to read, especially for deeply nested types.
The code is in my Github
TLDR
Extended Property Patterns make it easier to write filtering expressions on complex objects.
This is Day 27 of the 30 Days Of .NET 6 where every day I will attempt to explain one new / improved thing in the new release of .NET 6.
Happy hacking!