C# > Functional Programming > Pattern Matching > Positional Patterns
Positional Pattern Matching with Tuples in C#
This snippet demonstrates positional pattern matching in C# using tuples. Positional patterns allow you to deconstruct types based on their position, simplifying code and making it more readable, especially when dealing with data structures like tuples or custom classes with a defined deconstructor.
Basic Positional Pattern Matching
This example defines a method `GetShapeType` that takes a tuple representing the width and height of a shape. The `switch` expression uses positional patterns to match different shapes based on the values in the tuple. It first checks for a point (0, 0), then for a square (width equals height), and finally for rectangles with different width/height relationships. `var` keyword is used to capture the values and use them inside the `when` clause.
public static string GetShapeType((int Width, int Height) shape) =>
shape switch
{
(0, 0) => "Point",
(var w, var h) when w == h => "Square",
(var w, var h) when w > h => "Rectangle (Width > Height)",
(var w, var h) => "Rectangle (Width <= Height)",
};
// Usage
Console.WriteLine(GetShapeType((0, 0))); // Output: Point
Console.WriteLine(GetShapeType((5, 5))); // Output: Square
Console.WriteLine(GetShapeType((10, 5))); // Output: Rectangle (Width > Height)
Console.WriteLine(GetShapeType((5, 10))); // Output: Rectangle (Width <= Height)
Concepts Behind Positional Pattern Matching
Positional pattern matching builds upon the concept of deconstruction. A type that supports deconstruction exposes a `Deconstruct` method. The pattern matching engine uses this method to extract the values from the object into the specified positions. In the case of tuples, deconstruction is automatically supported. For custom types, you need to define a `Deconstruct` method.
Custom Type Deconstruction
This example shows how to define a `Deconstruct` method for a custom class `Point`. This allows you to use positional pattern matching with `Point` objects. The `Deconstruct` method takes `out` parameters that correspond to the values you want to extract from the object. Discards (`_`) are used to ignore values that are not relevant for a particular pattern. It also demonstrates relational patterns, such as `> 0` and `< 0`.
public class Point
{
public int X { get; set; }
public int Y { get; set; }
public Point(int x, int y)
{
X = x;
Y = y;
}
public void Deconstruct(out int x, out int y)
{
x = X;
y = Y;
}
}
public static string GetPointQuadrant(Point point) =>
point switch
{
(> 0, > 0) => "Quadrant I",
(< 0, > 0) => "Quadrant II",
(< 0, < 0) => "Quadrant III",
(> 0, < 0) => "Quadrant IV",
(0, _) => "On Y-axis",
(_, 0) => "On X-axis",
_ => "Origin"
};
// Usage
Console.WriteLine(GetPointQuadrant(new Point(1, 1))); // Output: Quadrant I
Console.WriteLine(GetPointQuadrant(new Point(0, 5))); // Output: On Y-axis
Console.WriteLine(GetPointQuadrant(new Point(0, 0))); // Output: Origin
Real-Life Use Case
Positional pattern matching is particularly useful when processing data from external sources, such as CSV files or databases, where the order of fields is well-defined. It can also simplify complex logic that involves multiple conditions based on the properties of an object. Consider parsing coordinates or geometrical data.
Best Practices
Interview Tip
Be prepared to explain the difference between positional and property patterns. Positional patterns rely on the order of values returned by a `Deconstruct` method (or are intrinsically defined like in a Tuple), while property patterns match based on the names of properties. Also, understand the role of the `Deconstruct` method in enabling positional pattern matching for custom types.
When to use them
Use positional patterns when:
Alternatives
Alternatives to positional pattern matching include:
Pros
Cons
FAQ
-
What is a `Deconstruct` method?
A `Deconstruct` method is a method that decomposes an object into its constituent parts. It takes `out` parameters that represent the values you want to extract from the object. -
Can I use positional patterns with any type?
You can use positional patterns with types that support deconstruction, either implicitly (like tuples) or explicitly (by defining a `Deconstruct` method). -
What is the underscore `_` used for in positional patterns?
The underscore `_` is a discard. It's used to indicate that you are not interested in a particular value in the pattern. It improves readability by making it clear which values are relevant.