✨ Shield now has support for Avalonia UI

C# Pattern Matching: Full Guide

Jul 25, 2023 | C#, .NET

Picture having an exclusive decoder key that not only unlocks your complex code problems but also significantly enhances your productivity. That’s precisely the magic wand, namely pattern matching in C#, brings to your programming world. But wait, how exactly does it achieve this? Stick around as we unravel this mysterious versatile feature in the C# language!

Introduction to Pattern Matching in C#

You’re probably wondering, what is pattern matching in C#, and why should I add it to my toolbox? Worry not; we’re about to set the record straight on that!

What is Pattern Matching?

Pattern matching in C# is a feature that allows you to implement method dispatch on properties other than the type of an object. In simpler terms, pattern matching allows you to check a given sequence of tokens for the presence of the constituents of some pattern. It’s like an advanced switch statement but with superpowers. So, are we ready to step out of our comfort zones and explore this new code frontier?

Advantages of Using Pattern Matching in C#

Using pattern matching in your C# code brings an array of benefits to your table, and few of them are:

  • Enhanced readability
  • Reduction in lines of code
  • Improved maintainability
  • More ways to express your algorithms

Seems quite handy, right? And it gets better! Let’s dive into the basics!

Types of Pattern Matching in C#

Familiarizing ourselves with these three basic pattern types is like setting the foundation stone of our pattern matching empire. Let’s get to it!

Constant Patterns

Constant patterns are pretty straightforward, they check if the incoming value equals a constant value. To illustrate this, consider the code below:

object o = "Hello, World!";
if(o is "Hello, World!") //This is a constant pattern
{
    Console.WriteLine($"Constant pattern matched.");
}

In the example, we’re testing if the object ‘o’ equals the string constant “Hello, World!”. That’s pretty straight forward, right? Onwards to the next!

Variable Patterns

Things start getting interesting with variable patterns. They not only test the type of a value, but also conveniently assign it to a new variable for you.

object o = "Hello, World!";
if(o is string message) //This is a variable pattern
{
    Console.WriteLine($"{message}");  
}

Isn’t it neat? But hold onto your hats, folks; it’s about to get way more thrilling!

Type Patterns

Type patterns permit you to match on the type of the object. Consider the following example:

public void Display(object o)
{
    if (o is int i) Console.WriteLine($"It’s an int with a value of {i}");
    else if (o is string s) Console.WriteLine($"It’s a string with a value of {s}");
}

Isn’t that fantastic? It’s like a “who am I” game for your code!

Delving into More Complex Patterns

Alright, hang in tight as we’re ready to explore the wilderness of the more complex pattern types!

Tuple Patterns

Tuple patterns allow you to match on the structure of tuples, like so:

(var x, 3) = (5, 3);  // Matches any value for x as long as the second item is 3

The power of tuples, right? They make complex tasks seem like child’s play!

Property Patterns

Property Patterns allow us to access an object’s properties to perform a match. Interested in how that works?

public class Employee
{
    public string Department { get; set; }
}

var john = new Employee { Department = "Human Resources" };

if (john is { Department: "Human Resources" })
{
    Console.WriteLine("John works in HR");
}

Isn’t it a handy way to gain insights directly from your objects?

Nested Properties Patterns

Nested Properties Patterns make the scenario a bit more intense by allowing you to match nested properties like this:

public class Company 
{
    public Employee Employee { get; set; }
}

if (company is { Employee.Department: "Human Resources" })
{
    Console.WriteLine("An employee works in HR");
}

Mind-blowing, isn’t it? Now we really are leaving no stone unturned!

Special Pattern Matching Techniques in C#

Up next, we are going to dig deeper into some special pattern-matching maneuvers. Shall we?

Discard Patterns

In C#, the discard pattern _ is a particular pattern that always matches its input. Curious how?

if (o is _) 
{
    Console.WriteLine("The discard always matches");
}

Null Checks in Pattern Matching

Pattern matching is a smooth operator when it comes to checking if a variable is null, as shown below:

if (o is null) 
{
    Console.WriteLine("o is null");
}

And just like that, we have a fancy, efficient new way to perform null-checks!

How to Conduct Type Tests Efficiently

Pattern matching simplifies type-testing in C# by checking if a value is of a certain type and then casting that type. Do you want to see how?

object o = SomeMethod();

if (o is int i) 
{
    Console.WriteLine($"{i} is an integer");
}

We can finally say goodbye to verbose type-testing!

Comparing Discrete Values Using Pattern Matching

In C#, comparisons aren’t just limited to null checks or type tests! You can use pattern matching to compare discrete values. Here’s how:

int? maybe = SomeValueReturningMethod();

if (maybe is int value && (value > 0 && value <=100)) 
{
    //do something with value
}

Doesn’t that give you a bigger bang for your buck?

Advanced Pattern Matching Concepts in C#

Alright, get ready! Here’s where things get truly exciting. Let’s now explore some advanced pattern matching concepts.

Relational Patterns

Relational patterns in C# allow us to match values based on their relation to other values as shown in the example below:

public static string DescribeLifeStage(int age) 
=> age switch
{
    < 2 => "Infant",
    < 4 => "Toddler",
    < 6 => "Early childhood",
    _ => "Older"
};

Can you imagine the sheer power relational patterns bring to your code?

Multiple Patterns

There might be situations where multiple patterns cater the same expression, and one can easily handle such instances like this:

char c = GetACharacterFromSomewhere();
return c switch
{
    'a' or 'e' or 'i' or 'o' or 'u' => "Vowel",
    _ => "Not a vowel"
};

Coding in C# definitely can’t get more thrilling than this, presenting multiple patterns!

List Patterns

Our friend, pattern matching, even extends its charm to arrays and collections in the form of list patterns. Check this out!

int[] numbers = { 1, 2, 3, 4 };

foreach (var number in numbers)
{
    if (number is (>= 1 and <= 10))
    {
        Output(number);
    }
}

It’s astonishing how pattern matching enables us to take such complex logic and make it so clean and readable, isn’t it?

Utilizing Pattern Matching in C#: Practical Examples

A Simple Yet Effective Example of Pattern Matching in C#

Let’s dive into a practical scenario of deciphering shapes using pattern matching:

abstract class Shape
{
    public abstract double Area { get; }
}

class Circle : Shape
{
    public override double Area { get; }
    public double Radius { get; }

    public Circle(double radius)
    {
        Radius = radius;
        Area = Math.PI * Math.Pow(radius, 2);
    }
}

class Rectangle : Shape
{
    public override double Area { get; }
    public double Width { get; }
    public double Height { get; }

    public Rectangle(double width, double height)
    {
        Width = width;
        Height = height;
        Area = width * height;
    }
}

public string DisplayShape(Shape shape)
{
    return shape switch
    {
        Circle c  => $"Circle with radius {c.Radius}",
        Rectangle r => $"Rectangle with width {r.Width} and height {r.Height}",
        _ => "Unknown shape"
    };
}

An Example of Pattern Matching with Multiple Inputs

The real treat of pattern matching is its versatility to accommodate multiple inputs:

public static RGBColor FromRainbow(Rainbow colorBand) =>
colorBand switch
{
    Rainbow.Red => new RGBColor(0xFF, 0x00, 0x00),
    Rainbow.Orange => new RGBColor(0xFF, 0x7F, 0x00),
    Rainbow.Yellow => new RGBColor(0xFF, 0xFF, 0x00),
    Rainbow.Green => new RGBColor(0x00, 0xFF, 0x00),
    Rainbow.Blue => new RGBColor(0x00, 0x00, 0xFF),
    Rainbow.Indigo => new RGBColor(0x4B, 0x00, 0x82),
    Rainbow.Violet => new RGBColor(0x94, 0x00, 0xD3),
};

Now, isn’t that the ultimate convenience you ever dreamt of?

Conclusion about Pattern Matching in C#

In this journey, we’ve shed light on this extraordinary feature named Pattern Matching in C#. By now, you’re not just aware of it, but you’ve unlocked its full potential and are ready to utilize it in your next project!

While it’s undeniably powerful and transformative, remember, pattern matching is a tool in your developer arsenal. It doesn’t necessarily make other tools obsolete or less important. The true wisdom lies in knowing when and where to use each tool for maximum effectiveness and optimized solutions.

As we bid adieu, remember, mastering any concept takes practice. So why wait? Roll up your sleeves, and start making your C# code better, faster and, of course, more fun with pattern matching!

You May Also Like