Pattern Matching in c#

Pattern matching is about examining an object and its properties and making decisions based on what we are looking for.

Pattern matching can turn a complex if-else or switch statement into a compact block of code.

Let's take a look at some examples

Constant Pattern

We can use constant pattern matching to determine if a variable has a constant value. The types that match are strings, chars, numbers, and enums.

var input = 5;

var result = input switch
{
     1 => "one",
    2 => "two",
    3 => "three",
    4 => "four",
    5 => "five",
};

And the compiler throws me this warning.

The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '""' is not covered.

Not every number is included in the above code, so we need to have a fallback option. The discard operator (_) is useful in these cases. It is invoked when none of the previous patterns match.

var input = 5;

var result = input switch
{
    1 => "one",
    2 => "two",
    3 => "three",
    4 => "four",
    5 => "five",
    _ => throw new Exception("Number not found")
};

a "when" statement can be added to the pattern to add an extra guard to the pattern.

var input = 5;
var result = input switch
{
    _ when input < 0 => "negative number",
    1 => "one",
    2 => "two",
    3 => "three",
    4 => "four",
    5 => "five",
    _ => throw new Exception("Number not found")
};

Matched value can also be assigned to a variable

var input = 6;

var result = input switch
{
    _ when input < 0 => "negative number",
    1 => "one",
    2 => "two",
    3 => "three",
    4 => "four",
    5 => "five",
    var number when number > 5 => $"{number} greater then 5",
     _ => throw new Exception("Number not found")
};

Relational Pattern

In relation pattern we can use any of the relational operators (<, >, <=, or >=)

var input = 5;

var result = input switch
{
    (< 3) => "Less than 3",
    _ => "Greater than 3"
};

If we add any unreachable pattern like below

var input = 5;

var result = input switch
{
    (< 3 ) => "Less than 3",
    (< 2) => "Less than 2"

};

Compiler throws the error to fix address the issue

Error    CS8510 The pattern is unreachable. It has already been handled by a previous arm of the switch expression or it is impossible to match.

Let's fix this mistake by changing the order (Order matters)

var input = 5;

var result = input switch
{
    (< 2) => "Less than 2",
    (< 3) => "Less than 3",
    _ => "Greater than 3"
};

Logical patterns

To combine patterns or to negate values, we use the logical operators (and, or, not).

var input = 15;

var result = input switch
{

    (< 2) => "Less than 2",
    (< 3) => "Less than 3",
    (> 4 and < 6) => "Between 4 and 6 ",
    not 9 => "number is not 9"
};

Tuple Pattern

We can use tuples to pattern match multiple input values when we want to match multiple values instead of matching single values.

var result = (isaccountactive, amountWithinTheLimit) switch
{
    (false, _) => "Inactive account",
    (true, false) => "Insufficient balance",
    (true, true) => "Transaction successful"
};

Property / Extended Property patterns

We can add a pattern to the properties of an object.

public class Person
{
    public String FirstName { get; set; }
    public String LastName { get; set; }
    public Address Address { get; set; }
}

public class Address
{
    public String City { get; set; }
    public String State { get; set; }

    public String Landmark { get; set; }

}
var result = (Person person) =>
   person switch
   {
       { Address.State: "TamilNadu" } => "Person is from TamilNadu",
       _ => "Person is not from TamilNadu"
   };

Ref :

https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/pattern-matching

https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/patterns-objects

https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/tutorials/pattern-matching