Switch Expressions and Pattern Matching in C#
Switch expressions and pattern matching in C# provide short ways to handle different conditions and types. These features, introduced in C# 8.0 and enhanced in later versions, also switch expressions and pattern matching allowing for more readable and maintainable code.
Switch Expressions
Switch expressions are a short form of the traditional switch statement, allowing us to return values directly from the switch cases.
public string GetDayType(DayOfWeek day) => day switch
{
DayOfWeek.Saturday => "Weekend",
DayOfWeek.Sunday => "Weekend",
DayOfWeek.Monday => "Weekday",
DayOfWeek.Tuesday => "Weekday",
DayOfWeek.Wednesday => "Weekday",
DayOfWeek.Thursday => "Weekday",
DayOfWeek.Friday => "Weekday",
_ => throw new ArgumentOutOfRangeException(nameof(day), $"Not expected day value: {day}")
};
In this example, the switch expression directly returns a string based on the DayOfWeek
enum value. The _
case handles any unexpected values.
Pattern Matching
Pattern matching allows us to match data structures against patterns. It is particularly useful in conjunction with switch expressions.
Type Patterns
Type patterns match the type of an expression and cast it if the match is successful.
public void PrintObjectInfo(object obj)
{
switch (obj)
{
case string s:
Console.WriteLine($"It's a string of length {s.Length}");
break;
case int i:
Console.WriteLine($"It's an integer with value {i}");
break;
case null:
Console.WriteLine("It's null");
break;
default:
Console.WriteLine("It's some other type");
break;
}
}
Property Patterns
Property patterns match the properties of an object.
public string DescribePerson(Person person) => person switch
{
{ Age: < 18 } => "Child",
{ Age: >= 18, Age: < 65 } => "Adult",
{ Age: >= 65 } => "Senior",
_ => "Unknown"
};
Positional Patterns
Positional patterns work with deconstructable types, allowing for tuple-like matching.
public string GetQuadrant(Point point) => point switch
{
(0, 0) => "Center",
var (x, y) when x > 0 && y > 0 => "Top-right",
var (x, y) when x < 0 && y > 0 => "Top-left",
var (x, y) when x < 0 && y < 0 => "Bottom-left",
var (x, y) when x > 0 && y < 0 => "Bottom-right",
_ => "On Axis or Undefined"
};
public record Point(int X, int Y);
In this example, the Point
record type is deconstructed directly in the switch expression.
Combining Patterns
You can also combine patterns using logical patterns such as and
, or
, and not
.
public string ClassifyNumber(int number) => number switch
{
< 0 => "Negative",
0 => "Zero",
> 0 and < 10 => "Positive single digit",
>= 10 and < 100 => "Positive double digit",
_ => "Positive large number"
};
The below example shows combining various pattern-matching techniques:
public string EvaluateScore(object score) => score switch
{
int x when x >= 90 => "Excellent",
int x when x >= 75 => "Good",
int x when x >= 50 => "Pass",
int x when x < 50 => "Fail",
double d when d >= 90.0 => "Excellent",
double d when d >= 75.0 => "Good",
double d when d >= 50.0 => "Pass",
double d when d < 50.0 => "Fail",
string s when double.TryParse(s, out double result) => EvaluateScore(result),
null => "No score provided",
_ => "Invalid score"
};
In this example, the method EvaluateScore
can handle integers, doubles, strings, and null values.
Comments (0)