Pattern matching is a powerful feature introduced in C# 7 that has only grown in capability with each new release. With C# 9, Microsoft has taken it to the next level by introducing recursive pattern matching, allowing you to match and destructure nested data structures more easily. In this post, we’ll dive into the concept of recursive pattern matching and illustrate it with real-world examples.
What is Recursive Pattern Matching?
Recursive pattern matching in C# 9 extends the existing pattern matching feature to work with nested data structures. It enables you to destructure and match objects within objects, making your code cleaner and more expressive. This is particularly useful when dealing with complex data hierarchies, such as JSON or XML documents.
Let’s get into the details with a real-world example: parsing JSON data.
Example: Parsing JSON with Recursive Pattern Matching
Consider you have a JSON document representing a person’s information:
{ "name": "John Doe", "age": 30, "address": { "street": "123 Main St", "city": "Anytown", "zip": "12345" } }
You want to parse this JSON and extract the person’s name and address information. Recursive pattern matching makes this task more straightforward and concise.
Here’s how you can achieve this using C# 9’s recursive pattern matching:
void Main()
{
var json = "{\"name\":\"John Doe\",\"age\":30,\"address\":{\"street\":\"123 Main St\",\"city\":\"Anytown\",\"zip\":\"12345\"}}";
var person = JsonSerializer.Deserialize<Person>(json);
if (person is { Name: var name, Address: { City: "Anytown" } })
{
Console.WriteLine($"Name: {name}");
Console.WriteLine("Lives in Anytown");
}
}
public class Person
{
[JsonPropertyName("name")]
public string Name { get; set; }
[JsonPropertyName("age")]
public int Age { get; set; }
[JsonPropertyName("address")]
public Address Address { get; set; }
}
public class Address
{
[JsonPropertyName("street")]
public string Street { get; set; }
[JsonPropertyName("city")]
public string City { get; set; }
[JsonPropertyName("zip")]
public string Zip { get; set; }
}
In this code, we use the JsonSerializer
to deserialize the JSON data into a Person
object. We then employ recursive pattern matching to check if the person’s address includes a “City” with the value “Anytown.” If the match is successful, we extract and print the person’s name and a message about their location.
Recursive pattern matching allows us to navigate the nested structure of the Person
object and its Address
property in a clean and expressive way.
Handling Variants with Recursive Pattern Matching
Recursive pattern matching is not limited to simple data structures. It’s also great for handling more complex data variants. Let’s consider a real-world example involving geometric shapes.
Imagine you have a program that works with various geometric shapes, such as circles, squares, and triangles. You want to calculate the area of each shape. Here’s how you can use recursive pattern matching for this:
public interface IShape { }
public record Circle(double Radius) : IShape;
public record Square(double Side) : IShape;
public record Triangle(double Base, double Height) : IShape;
public static double CalculateArea(IShape shape) => shape switch
{
Circle { Radius: var r } => Math.PI * r * r,
Square { Side: var s } => s * s,
Triangle { Base: var b, Height: var h } => 0.5 * b * h,
_ => 0.0 // Handle unknown shapes
};
In this example, we define different shapes using records and a common interface IShape
. The CalculateArea
function takes an IShape
and uses recursive pattern matching to calculate the area based on the type of shape. If the shape is not recognized, it returns 0.0.
Conclusion
Recursive pattern matching in C# 9 is a powerful tool that simplifies working with nested and complex data structures. It allows you to match and destructure objects within objects, making your code more readable and expressive. Whether you’re parsing JSON or handling complex data variants, recursive pattern matching can greatly improve your code.
As C# continues to evolve, features like recursive pattern matching demonstrate the language’s commitment to improving developer productivity and code quality.
So, the next time you encounter nested data structures or variants in your C# code, consider using recursive pattern matching to simplify your logic and make your code more elegant.
Happy coding!