C# Advanced

C# 7 Switch Pattern Matching

C# 7 Switch Pattern Matching
Table of Contents

The switch Pattern Matching

When it comes to switch statements, match expressions were limited to comparing a variable to a constant value (constant pattern). C# 7 supports switch type pattern matching, where case clause can match the type of variable being checked and is no longer limited to numeric types and the string type. 

Now you can switch on any type because restrictions on variable types have been removed from switch expressions. Let’s look at how to implement pattern matching in the following code examples.

Note: You can use return or break statements but type pattern does not support goto statement. Constant pattern supports goto statement.

By the end of this article, you’ll know:

  • What switch type pattern matching is and how to use it
  • How to expand switch case statement to check for types
  • How to use when guard with switch case statements to perform more specific pattern matching on the variable
  • How to check null values passed to the switch statement.

Ready? Let’s get started!


C# 7 Switch Pattern Matching Example

Let’s create two new classes called Fruit and Vegetable to illustrate the concept of pattern matching in switch statements. The code for the Fruit and Vegetable class is as follows.

public class Fruit
{
    public string Name{get; set;}
    public int Quantity{get; set;}
    
    public Fruit(string name, int quantity){
        Name = name;
        Quantity = quantity;
    }
}

public class Vegetable
{
    public string Name{get; set;}
    public Vegetable(string name){
        Name = name;
    }
}

Now create PrintInfo() method to include a boilerplate code of a switch statement.

public static void PrintInfo(object food)
{
  switch (food)
  {

    default:
      Console.WriteLine("Food info not found.");
      break;
  }
}

Note: The food variable is an object because object type allows for a variable of any type.


C# 7 switch With Type Pattern

Now, expand the case statement to check for the Fruit and Vegetable types. If an object matches with any of the twotypes, it then acts on that object and uses its type in the body of the case statement. This allows you to call the type-specific Name and Quantity properties. Let’s change PrintInfo() method to reflect the new changes:

public static void PrintInfo(object food)
{
	switch (food)
	{
		case Fruit item:
			Console.WriteLine($"{item.Name} is a {nameof(Fruit)}. Quantity available {item.Quantity}.");
			break;
		case Vegetable item:
			Console.WriteLine($"{item.Name} is a {nameof(Vegetable)}.");
			break;
		default:
			Console.WriteLine("Food info not found.");
			break;
	}
}

Depending on the type of the food variable, different case statements are matched.

Note: The order of the case clauses is now significant when switching on type.


C# 7 switch With case Statement and when Clause

Another feature of case statements is the use of when guard, which can be added to perform more specific pattern matching on the variable. Besides checking the type, the value of the type is also checked for a match.For the first case statement in the switch structure below, the item would only be a match if the food is a type Fruit and its Quantity property is equal to 0 and output a different result based on that. Consider the following code.

public static void PrintInfo(object food)
{
	switch (food)
	{
		case Fruit item when (item.Quantity == 0):
			Console.WriteLine($"{item.Name} is a {nameof(Fruit)}. Out of Stock.");
			break;
		case Fruit item:
			Console.WriteLine($"{item.Name} is a {nameof(Fruit)}. Quantity available {item.Quantity}.");
			break;
		case Vegetable item:
			Console.WriteLine($"{item.Name} is a {nameof(Vegetable)}.");
			break;
		default:
			Console.WriteLine("Food info not found.");
			break;
	}
}

C# 7 switch With null Case Statement

You can also check for null values by adding a null case. This ensures that the argument passed to the switch statement is not null. Now the completed switch statement is as follows.

public static void PrintInfo(object food)
{
	switch (food)
	{
		case Fruit item when (item.Quantity == 0):
			Console.WriteLine($"{item.Name} is a {nameof(Fruit)}. Out of Stock.");
			break;
		case Fruit item:
			Console.WriteLine($"{item.Name} is a {nameof(Fruit)}. Quantity available {item.Quantity}.");
			break;
		case Vegetable item:
			Console.WriteLine($"{item.Name} is a {nameof(Vegetable)}.");
			break;
		case null:
			Console.WriteLine("Invalid food.");
			break;
		default:
			Console.WriteLine("Food info not found.");
			break;
	}
}

Run Demo

OUTPUT

Apple is a Fruit. Out of Stock.
Peach is a Fruit. Quantity available 12.
Potato is a Vegetable.
Invalid food.


C# 7 Switch Pattern Matching Example

using System;
using System.Collections.Generic;

public class Program
{
 public static void Main()
 {
       GetType(3);
       GetType("Hi");
       GetType(false);
       GetType(2.5f);
       GetType(new List<string>());
       GetType(null);
       GetType(3.5);
 }

 static void GetType(object obj)
   {
       switch (obj)
       {
           case int i:
               Console.WriteLine($"{i} is an integer.");
               break;
           case string s:
               Console.WriteLine($"{s} is a string.");
               break;
           case bool b:
               Console.WriteLine($"{b} is a Boolean.");
               break;
           case float f:
               Console.WriteLine($"{f} is a float.");
               break;
           case List<string> l:
               Console.WriteLine($"{l} is a List object.");
               break;
           case null:
               Console.WriteLine("Value is null.");
               break;
           default:
               Console.WriteLine("Invalid datatype");
               break;
       }
   }
}

Run Demo

OUTPUT

3 is an integer.
Hi is a string.
False is a Boolean.
2.5 is a float.
System.Collections.Generic.List`1[System.String] is a List object.
Value is null.
Invalid datatype