Pattern Matching in C#
Understanding Pattern Matching in C#
**Pattern Matching** in C# allows for more **concise, readable, and expressive** code by testing values against patterns. Introduced in **C# 7.0** and enhanced in later versions, pattern matching enables **type checking, conditional assignments, and deconstruction** in a more elegant way.
Key Features of Pattern Matching
- Allows **conditional type checking and assignment**.
- Eliminates the need for **explicit type casting**.
- Supports **switch expressions, `is` operator, and tuple patterns**.
- Simplifies **object deconstruction and property testing**.
Using `is` Pattern Matching
The `is` keyword allows checking the **type of an object** and casting it **simultaneously**.
Example: Checking and Casting with `is`
using System;
class Program
{
static void Main()
{
object value = "Hello, C#";
if (value is string text)
{
Console.WriteLine($"String Length: {text.Length}");
}
}
}
// Output:
// String Length: 9
Instead of **explicit casting (`(string)value`)**, `is` pattern matching automatically **checks and assigns** the variable.
Switch Pattern Matching
**Pattern Matching with `switch`** enables more **concise and readable** conditional statements.
Example: Switch Pattern Matching
using System;
class Program
{
static void Main()
{
Console.WriteLine(GetShapeArea(new Circle(5)));
Console.WriteLine(GetShapeArea(new Rectangle(4, 6)));
}
static double GetShapeArea(object shape) => shape switch
{
Circle c => Math.PI * c.Radius * c.Radius,
Rectangle r => r.Width * r.Height,
_ => throw new ArgumentException("Unknown shape")
};
}
record Circle(double Radius);
record Rectangle(double Width, double Height);
// Output:
// 78.53981633974483
// 24
The **switch expression** eliminates **boilerplate `case` blocks**, making the code **cleaner and more readable**.
Property Pattern Matching
**Property patterns** allow matching **specific properties** of an object instead of its entire type.
Example: Using Property Patterns
using System;
class Program
{
static void Main()
{
Person person = new("Alice", 30);
if (person is { Age: >= 18 })
{
Console.WriteLine($"{person.Name} is an adult.");
}
}
}
record Person(string Name, int Age);
// Output:
// Alice is an adult.
The **property pattern** `{ Age: >= 18 }` allows matching based on **specific property values**.
Tuple Pattern Matching
**Tuple patterns** allow matching multiple values inside a tuple, simplifying complex conditions.
Example: Tuple Pattern Matching
using System;
class Program
{
static void Main()
{
Console.WriteLine(DescribeWeather(30, true));
Console.WriteLine(DescribeWeather(10, false));
}
static string DescribeWeather(int temperature, bool isRaining) => (temperature, isRaining) switch
{
(> 25, true) => "Hot and rainy",
(> 25, false) => "Hot and dry",
(< 15, _) => "Cold",
_ => "Moderate"
};
}
// Output:
// Hot and rainy
// Cold
**Tuple patterns** simplify multiple conditions into a **clean and readable** format.
Best Practices for Using Pattern Matching
- Use **`is` pattern matching** to avoid unnecessary **type casting**.
- Use **switch expressions** for **more readable conditionals**.
- Use **property patterns** when matching based on **specific object properties**.
- Use **tuple patterns** for **multiple value comparisons** in a concise way.
- Ensure **patterns are exhaustive** to handle all possible cases properly.