C# > Language Features by Version > C# 6 to C# 12 Highlights > Pattern Matching Enhancements (C# 8+)
Positional Pattern Matching with Tuples
This snippet illustrates positional pattern matching, often used with tuples, to deconstruct objects based on their position (order) of properties. C# supports deconstructing custom types via `Deconstruct` methods. We'll look at a simple example using tuples and expand to demonstrate custom deconstruction.
Positional Pattern Matching with Tuples
This code defines a method `DescribePoint` that takes a tuple of two integers representing a point's coordinates. It uses a `switch` expression with positional pattern matching to determine the location of the point. The order of the tuple elements is crucial; the first element is matched against the first position in the pattern, the second against the second, and so on. The `when` clause is used to further refine the matching based on the values of `x` and `y`.
using System;
public static class PositionalPatternMatchingDemo
{
public static string DescribePoint((int x, int y) point)
{
return point switch
{
(0, 0) => "Origin",
(var x, 0) => $"X-axis with x = {x}",
(0, var y) => $"Y-axis with y = {y}",
(var x, var y) when x > 0 && y > 0 => $"Quadrant I ({x}, {y})",
(var x, var y) => $"Other location ({x}, {y})"
};
}
public static void Main(string[] args)
{
Console.WriteLine(DescribePoint((0, 0)));
Console.WriteLine(DescribePoint((5, 0)));
Console.WriteLine(DescribePoint((0, 10)));
Console.WriteLine(DescribePoint((3, 4)));
Console.WriteLine(DescribePoint((-1, -2)));
}
}
Positional Pattern Matching with Custom Types
This code defines a `Point` class and a `Deconstruct` method. The `Deconstruct` method allows us to deconstruct a `Point` object into its `X` and `Y` components for use in positional pattern matching. The `DescribePoint` method now accepts a `Point` object and uses the same positional patterns as before, but thanks to the `Deconstruct` method, it can directly access the `X` and `Y` coordinates of the `Point` object within the `switch` expression.
using System;
public class Point
{
public int X { get; set; }
public int Y { get; set; }
public void Deconstruct(out int x, out int y)
{
x = X;
y = Y;
}
}
public static class CustomPositionalPatternMatchingDemo
{
public static string DescribePoint(Point point)
{
return point switch
{
(0, 0) => "Origin",
(var x, 0) => $"X-axis with x = {x}",
(0, var y) => $"Y-axis with y = {y}",
(var x, var y) when x > 0 && y > 0 => $"Quadrant I ({x}, {y})",
(var x, var y) => $"Other location ({x}, {y})"
};
}
public static void Main(string[] args)
{
Point origin = new Point { X = 0, Y = 0 };
Point xAxis = new Point { X = 5, Y = 0 };
Point yAxis = new Point { X = 0, Y = 10 };
Point quadrantI = new Point { X = 3, Y = 4 };
Point other = new Point { X = -1, Y = -2 };
Console.WriteLine(DescribePoint(origin));
Console.WriteLine(DescribePoint(xAxis));
Console.WriteLine(DescribePoint(yAxis));
Console.WriteLine(DescribePoint(quadrantI));
Console.WriteLine(DescribePoint(other));
}
}
Concepts Behind the Snippet
Positional pattern matching allows for deconstructing an object into its constituent parts and matching based on the position of those parts. This is particularly useful for working with tuples or custom types that implement a `Deconstruct` method. The `Deconstruct` method defines how an object can be broken down into its components for pattern matching purposes.
Real-Life Use Case
Consider a scenario where you're processing geographical data, and you have different types of geographical features (e.g., points, lines, polygons). Each feature type has a different set of coordinates. Positional pattern matching can be used to extract the coordinates of each feature and perform calculations based on their location. It also provides more clear and structured way to access properties than property pattern.
Best Practices
Alternatives
Alternative to positional pattern matching is to access properties of the tuple or custom type directly using the `.` operator (e.g., `point.x`, `point.y`). However, this approach is less concise and can be more error-prone. You could also use traditional `if-else` statements with property checks.
Pros
Cons
FAQ
-
What is a `Deconstruct` method?
A `Deconstruct` method is a special method that allows you to deconstruct an object into its constituent parts. It's used with positional pattern matching to extract the values of the object's properties based on their position. -
Can I use positional pattern matching with records?
Yes, records in C# implicitly provide a `Deconstruct` method based on the record's properties, making them ideal for positional pattern matching.