Since C# 7.0, the functionality of the switch statement has been significantly expanded to support Pattern Matching. This allows for not only simple constant matching but also type checking and detailed conditional logic using the when clause.
Complex conditional branching, which previously required chaining if-else statements, can now be structured and rewritten into highly readable code using switch.
In this article, I will introduce an implementation example that accepts object type input and distributes processing based on the type and value conditions (such as ranges).
Table of Contents
- Implementation Example: Complex Condition Checks with Types and Values
- Explanation and Key Points
- Summary
Implementation Example: Complex Condition Checks with Types and Values
The following code simulates processing a list containing mixed data types. Inside the switch statement, it uses the syntax case Type variable when Condition to perform type checking and value evaluation simultaneously.
using System;
namespace SwitchPatternExample
{
class Program
{
static void Main(string[] args)
{
// Data to process (mixed types including int, double, string, null)
object[] rawData = { 100, -5, 3.14, 0.01f, "Status OK", null };
Console.WriteLine("--- Data Analysis Start ---");
foreach (var data in rawData)
{
ProcessData(data);
}
}
static void ProcessData(object data)
{
switch (data)
{
// 1. Type pattern + when clause (Guard condition)
// If it is an int and the value is 1 or greater
case int i when i >= 1:
Console.WriteLine($"[Positive Integer] Value: {i}");
break;
// 2. Same int type but different condition
// Integers that did not match the above condition (>= 1) come here
case int i:
Console.WriteLine($"[Other Integer] Value: {i}");
break;
// 3. Fall-through for multiple case labels
// If double or float, AND the value is 1.0 or greater
// Logic can be shared even across different types
case double d when d >= 1.0:
case float f when f >= 1.0f:
Console.WriteLine($"[Real Number >= 1.0] Value: {data}");
break;
// 4. String with a specific value (Constant pattern)
case "Status OK":
Console.WriteLine("[Status] Normal.");
break;
// 5. Null check
case null:
Console.WriteLine("[Error] Data is null.");
break;
// 6. When no condition matches
default:
Console.WriteLine($"[Unsupported Type] {data.GetType().Name}");
break;
}
}
}
}
Explanation and Key Points
1. Type Pattern and Variable Declaration
By writing case int i, the code checks if the variable data is of type int. If it is, it safely casts the value and assigns it to the variable i. This variable i is valid only within that specific case block.
2. The when Clause (Guard Condition)
By writing case ... when condition, you can add detailed conditions (such as a value range) on top of the type check. This is called a “Guard Condition.”
case int i when i >= 1:
This feature allows validation logic based on data types to be neatly contained within the switch statement.
3. Order of Evaluation
The switch statement is evaluated from top to bottom. Therefore, strictly specific conditions (narrow ranges) must be written at the top, and looser conditions (general cases) at the bottom.
For example, if you write case int i: before case int i when i >= 1: in the code above, all integers will be caught by the first case, and the specific logic for positive integers will never be executed.
Summary
By using pattern matching combined with the when clause, the C# switch statement becomes a very powerful control structure.
- Type Safety: Eliminates the need for manual casting.
- Flexibility: Allows you to attach arbitrary conditions, such as value ranges or property states.
- Readability: Organizes complex logic that would otherwise look like
if (obj is int i && i >= 1) ....
Please actively use this feature in data processing where diverse input patterns are possible or when implementing state machines.
