- C# - Home
- C# - Overview
- C# - Environment
- C# - Program Structure
- C# - Basic Syntax
- C# - Data Types
- C# - Type Conversion
- C# - Variables
- C# - Constants
- C# - Operators
- C# - Arithmetic Operators
- C# - Assignment Operators
- C# - Relational Operators
- C# - Logical Operators
- C# - Bitwise Operators
- C# - Miscellaneous Operators
- C# - Operators Precedence
- C# Conditional Statements
- C# - Decision Making
- C# - If
- C# - If Else
- C# - Nested If
- C# - Switch
- C# - Nested Switch
- C# - Switch Expressions
- C# Control Statements
- C# - Loops
- C# - For Loop
- C# - While Loop
- C# - Do While Loop
- C# - Nested Loops
- C# - Break
- C# - Continue
- C# - Foreach Loop
- C# - Goto Statement
- C# OOP & Data Handling
- C# - Encapsulation
- C# - Methods
- C# - Nullables
- C# - Arrays
- C# - Strings
- C# - Structure
- C# - Enums
- C# - Classes
- C# - Inheritance
- C# - Polymorphism
- C# - Operator Overloading
- C# - Interfaces
- C# - Namespaces
- C# - Preprocessor Directives
- C# - Regular Expressions
- C# - Exception Handling
- C# - File I/O
- C# Advanced Tutorial
- C# - Attributes
- C# - Reflection
- C# - Properties
- C# - Indexers
- C# - Delegates
- C# - Events
- C# - Collections
- C# - Generics
- C# - LINQ
- C# - IEnumerable vs IEnumerator
- C# - Anonymous Methods
- C# - Unsafe Codes
- C# - Tasks and Parallel Programming
- C# - Multithreading
- C# - Extension Methods
C# - Switch Expressions (Pattern Matching)
In C#, switch expressions are a form of pattern matching that allow us to perform actions based on the first matching pattern of an expression. The switch expression in C# is a modern alternative to the traditional switch statement, introduced in C# 8.0. Improves the readability and conciseness compared to traditional switch statements.
It allows us to create simple, expression-based pattern-matching logic that returns a value. It's especially helpful for simplifying conditional logic and replacing difficult if-else or switch statements.
Switch expressions work smoothly with pattern matching, allowing you to match not only constant values, but also types, ranges, relational patterns, and complex conditions.
Let's compare the traditional switch statement vs. switch expression by a C# code −
Traditional Switch Statement vs. Switch Expression
Traditional Switch Statement − In the code below, we use a switch statement to display whether a given number corresponds to a weekday or a weekend.
using System;
class Program {
static void Main(){
int dayNumber = 4;
Console.WriteLine($"Day Number: {dayNumber}");
string dayType = GetDayType(dayNumber);
Console.WriteLine($"Day Type: {dayType}");
}
static string GetDayType(int dayNumber){
string result;
switch (dayNumber){
case 1:
case 7:
result = "Weekend";
break;
case 2:
case 3:
case 4:
case 5:
case 6:
result = "Weekday";
break;
default:
result = "Invalid Day";
break;
}
return result;
}
}
Following is the output of the above code −
Day Number: 4 Day Type: Weekday
Switch Expression: In the code below, we use a switch expression to display whether a given number corresponds to a weekday or a weekend.
using System;
class Program {
static void Main(){
int dayNumber = 4;
string dayType = GetDayType(dayNumber);
Console.WriteLine($"Day Number: {dayNumber}");
Console.WriteLine($"Day Type: {dayType}");
}
static string GetDayType(int dayNumber) =>
dayNumber switch {
1 or 7 => "Weekend",
>= 2 and <= 6 => "Weekday",
_ => "Invalid Day"
};
}
Following is the output −
Day Number: 4 Day Type: Weekday
Now, after comparing both the traditional switch statement and the switch expression, we have learned that the switch expression is better than the switch statement because it makes the code concise, readable, and supports pattern matching. Let's learn more about switch expression.
Benefits of Using Switch Expression
Following are the benefits of using switch expression −
- It is more concise and readable, understandable and less time-consuming.
- It returns a value directly.
- It uses pattern matching syntax.
- It eliminates repetitive break and return keywords.
Declaration of Switch Expression
In C#, switch expression uses a concise and expression-based declaration style, as shown below −
var result = input switch {
pattern1 => expression1,
pattern2 => expression2,
_ => defaultExpression
};
The above syntax contains the following variables and parameters −
- input − The value or variable being evaluated.
- pattern − The matching condition (constant, relational, or type pattern).
- expression − The value or result returned when the pattern matches.
- _(discard pattern) − It work like a default case if no other pattern matches.
Pattern Matching in Switch Expression
Switch expressions support several kinds of patterns for powerful matching logic.
- Constant Pattern
- Type Pattern
- Relational Pattern
- Logical Pattern (and, or, not)
- Property Pattern
- Positional Pattern (Deconstruction)
C# Constant Pattern
The constant pattern is a simpler way to compare a value with a fixed constant. It works like using the "==" operator to check if an expression equals a specific constant value.
In a constant pattern, you can use any constant expression, such as −
- an
integerorfloating-pointnumerical literal - a
char - a
stringliteral. - a Boolean value
trueorfalse - an
enumvalue - the name of a declared
constfield or local - null
The expression must be of a type that can be converted to the constant's type.
Example of Constant Pattern
In the following example we use the constant pattern inside the switch expression to compare the temperature with constant values −
using System;
class Program {
static void Main(){
int temperature = 25;
string condition = GetWeatherCondition(temperature);
Console.WriteLine($"Temperature: {temperature} deg C");
Console.WriteLine($"Weather Condition: {condition}");
}
// constant pattern
static string GetWeatherCondition(int temperature) =>
temperature switch{
0 => "Freezing",
25 => "Pleasant",
40 => "Hot",
_ => "Unknown"
};
}
Following is the output −
Temperature: 25 deg C Weather Condition: Pleasant
C# Type Pattern
A type pattern is used in a switch expression to check the runtime type of an object and optionally use it as that type inside the matching branch.
It helps us decide what to do based on the type of a variable or expression. For example, whether it's an int, string, double, or even a custom class.
Why We Use Type Pattern
- To perform different actions depending on the type of an object.
- To avoid manual type checking using is, as, or casting ((int)obj).
- To make the code cleaner and safer (no invalid type conversions).
Example of Type Pattern
In this example, the switch expression checks the type of objects' elements at runtime using the type pattern −
using System;
class Program {
static void Main(){
object value = 3.14;
string result = CheckObjectType(value);
Console.WriteLine($"Value: {value}");
Console.WriteLine($"Type: {result}");
}
static string CheckObjectType(object obj) =>
obj switch {
int => "Integer Type",
string => "String Type",
double => "Double Type",
_ => "Unknown Type"
};
}
Following is the output −
Value: 3.14 Type: Double Type
C# Relational Pattern
We use a relational pattern to compare an expression result with a constant.
In a relational pattern we can use any of the relational operators like <, >, <=, or >=. The right hand part of the relational pattern must be a constant expression. The constant expression can be of an integer, floating-point, char, or enum type.
Example of Relational Pattern
Following is the example of the relational pattern that compares the expression result with a constant.
using System;
class Program {
static void Main(){
Console.WriteLine(Classify(13));
Console.WriteLine(Classify(double.NaN));
Console.WriteLine(Classify(2.4));
}
static string Classify(double measurement) => measurement switch{
< -4.0 => "Too low",
> 10.0 => "Too high",
double.NaN => "Unknown",
_ => "Acceptable",
};
}
Following is the output −
Too high Unknown Acceptable
If an expression result is null or fails to convert to the type of a constant by a nullable or unboxing conversion, a relational pattern doesn't match an expression.
C# Logical Pattern (and, or, not)
The logical pattern let us combine multiple conditions in a switch expression using and, or, and not. It makes your pattern matching more flexible and expressive.
We use logical patterns for combining multiple conditions without writing the nested if-else statement. It works well with relational and type patterns.
Example of Logical Pattern
Following is the output −
In the following example, we display the age category using the logical pattern (and operator), without having to pass an if-else statement.
using System;
class Program {
static void Main(){
int age = 15;
string category = GetAgeCategory(age);
Console.WriteLine($"Age: {age}");
Console.WriteLine($"Category: {category}");
}
static string GetAgeCategory(int age) =>
age switch {
< 13 => "Child",
>= 13 and < 20 => "Teenager",
>= 20 and < 60 => "Adult",
>= 60 => "Senior"
};
}
Following is the output −
Age: 15 Category: Teenager
C# Property Pattern
We use a property pattern to match an expression's properties or fields against specific conditions (nested patterns). For example −
static bool IsConferenceDay(DateTime date) =>
date is { Year: 2020, Month: 5, Day: 19 or 20 or 21 };
It checks whether the expression is non-null and whether each nested pattern matches the corresponding property or field of the expression. If all conditions are satisfied, the property pattern is considered a match.
We can also add a run-time type check and a variable declaration to a property pattern.
Example of Property Pattern
This is a simple and clear example that shows how to add a run-time type check and a variable declaration inside a property pattern −
using System;
class Program {
static void Main(){
object person = new Person { Name = "Aman", Age = 25 };
string result = GetPersonInfo(person);
Console.WriteLine(result);
}
static string GetPersonInfo(object obj) =>
obj switch {
// Type check, property pattern, variable declaration
Person { Name: var name, Age: var age } => $"Person: {name}, Age: {age}",
_ => "Unknown object"
};
}
class Person {
public string Name { get; set; }
public int Age { get; set; }
}
Following is the output −
Person: Alice, Age: 25
C# Positional Pattern
The positional pattern is used to deconstruct an expression's result and match the individual values against their corresponding nested patterns.
Example of Positional Pattern
In the following example, we will see how the positional pattern is used to deconstruct the expression result.
using System;
public struct Point {
public int X { get; }
public int Y { get; }
// Constructor to initialize X and Y
public Point(int x, int y){
X = x;
Y = y;
}
// Deconstruct method allows splitting Point into (x, y)
public void Deconstruct(out int x, out int y){
x = X;
y = Y;
}
}
class Program{
static void Main(){
var p1 = new Point(0, 0);
var p2 = new Point(1, 0);
var p3 = new Point(3, 4);
Console.WriteLine(Classify(p1));
Console.WriteLine(Classify(p2));
Console.WriteLine(Classify(p3));
}
// Using positional pattern to match coordinates
static string Classify(Point point) => point switch {
(0, 0) => "Origin",
(1, 0) => "Positive X axis point",
(0, 1) => "Positive Y axis point",
_ => "Just a point"
};
}
Following is the output −
Origin Positive X axis point Just a point
In the above example, the type of an expression contains the Deconstruct method, which is used to deconstruct an expression result.
The order of members in a positional pattern must match the order of parameters in theDeconstructmethod. That's because the code generated for the positional pattern calls theDeconstructmethod.
Conclusion
To make your code more expressive, safer, and simpler, use switch expressions with pattern matching. They enable functional-style logic with clear intent, replacing traditional switch statements in most modern C# projects.