When it comes to making decisions in programming, developers often rely on conditional statements to control the flow of their code. One such statement that plays a crucial role in decision-making is the switch statement in C#. The switch statement provides a concise and readable way to handle multiple conditions, making code more maintainable and efficient.
Understanding the Basics
The switch statement evaluates an expression against a list of possible values and executes the corresponding block of code for the first match it finds. This makes it a powerful tool for simplifying code that would otherwise be cluttered with nested if-else statements.
Let’s start with a basic example to illustrate the syntax of a switch statement:
using System;
public class SwitchStatement
{
public static void Main(string[] args)
{
int dayOfWeek = 3;
switch (dayOfWeek)
{
case 1:
Console.WriteLine("It's Monday!");
break;
case 2:
Console.WriteLine("It's Tuesday!");
break;
case 3:
Console.WriteLine("It's Wednesday!");
break;
default:
Console.WriteLine("It's another day of the week.");
break;
}
}
}
In this example, the dayOfWeek variable is evaluated against various cases, and the corresponding code block is executed. If no match is found, the code in the default block is executed.
Simple Case Statements
Each case in a switch statement consists of a constant value or an expression, followed by a colon. The code block associated with a case is executed when the evaluated expression matches the specified constant value.
using System;
public class SwitchStatement
{
public static void Main(string[] args)
{
int number = 42;
switch (number)
{
case 1:
Console.WriteLine("One");
break;
case 42:
Console.WriteLine("Forty Two");
break;
default:
Console.WriteLine("Not found");
break;
}
}
}
Here, the code prints “Forty Two” since number is equal to 42.
Handling Multiple Conditions
One of the strengths of the switch statement is its ability to handle multiple conditions in a concise manner. Let’s say we want to categorize a given integer into different ranges:
using System;
public class SwitchStatement
{
public static void Main(string[] args)
{
int number = 42;
string category;
switch (number)
{
case int n when n < 0:
category = "Negative";
break;
case int n when n >= 0 && n <= 10:
category = "Between 0 and 10";
break;
case int n when n > 10 && n <= 20:
category = "Between 11 and 20";
break;
default:
category = "Invalid";
break;
}
Console.WriteLine($"The number is in the category: {category}");
}
}
In this example, the when clause is used to specify additional conditions for each case. This feature, introduced in C# 7.0, enhances the flexibility of the switch statement, allowing for more complex scenarios.
Case Ranges
One of the noteworthy features introduced in C# 7.0 is the ability to use case ranges within a switch statement. This allows for a more compact and expressive representation of consecutive values. Consider the following example:
using System;
public class SwitchStatement
{
public static void Main(string[] args)
{
int score = 85;
switch (score)
{
case >= 90:
Console.WriteLine("A");
break;
case >= 80 and < 90:
Console.WriteLine("B");
break;
case >= 70 and < 80:
Console.WriteLine("C");
break;
case >= 60 and < 70:
Console.WriteLine("D");
break;
default:
Console.WriteLine("F");
break;
}
}
}
In this example, we use the >= operator to create case ranges. The switch statement evaluates the value of score and executes the corresponding case. This enhancement not only reduces redundancy in the code but also makes it more readable and concise.
Strings in Switch
Starting from C# 7.0, the switch statement supports strings as well, providing a convenient way to compare string values. Let’s consider an example where we determine the type of a geometric shape based on its name:
using System;
public class SwitchStatement
{
public static void Main(string[] args)
{
string shape = "circle";
string type;
switch (shape)
{
case "circle":
type = "Round";
break;
case "square":
case "rectangle":
type = "Quadrilateral";
break;
default:
type = "Unknown";
break;
}
Console.WriteLine($"The shape is {type}");
}
}
In this case, if shape is “circle,” the output will be “The shape is Round.” The switch statement allows you to handle multiple string values efficiently.
Pattern Matching with Switch
C# 7 introduced pattern matching, enriching the switch statement with more expressive and powerful features. Instead of comparing values directly, you can use patterns to match and destructure them. Let’s explore an example using a simple geometric shape hierarchy:
using System;
public class SwitchStatement
{
public static void Main(string[] args)
{
object shape = "circle";
switch (shape)
{
case string circleName: // Match and destructure
Console.WriteLine($"This is a circle named {circleName}");
break;
case int rectangleSides when rectangleSides == 4:
Console.WriteLine("This is a rectangle");
break;
case int triangleSides when triangleSides == 3:
Console.WriteLine("This is a triangle");
break;
default:
Console.WriteLine("Unknown shape");
break;
}
}
}
In this example, the switch statement leverages pattern matching to extract information about the shape, allowing for more intricate and dynamic comparisons.
Switching on Types
The switch statement can also be used to switch on types, making it a versatile tool for handling polymorphic scenarios. Let’s consider an example where we process different types of objects in a collection:
using System;
using System.Collections.Generic;
public class SwitchStatement
{
static void ProcessObjects(List<object> objects)
{
foreach (var obj in objects)
{
switch (obj)
{
case string str:
Console.WriteLine($"String: {str}");
break;
case int num:
Console.WriteLine($"Integer: {num}");
break;
case double dbl:
Console.WriteLine($"Double: {dbl}");
break;
default:
Console.WriteLine($"Unknown type: {obj.GetType().Name}");
break;
}
}
}
public static void Main(string[] args)
{
List<object> objects = new List<object>
{
"Hello, C#",
42,
3.14,
true
};
ProcessObjects(objects);
}
}
In this example, the switch statement dynamically matches the type of each object, allowing us to handle them differently based on their inherent characteristics.
Advanced Techniques: Switch Expression
C# 8 introduced the switch expression, a more concise and expressive form of the switch statement. It can be used in a variety of scenarios, including as an expression within a method. Let’s refactor the shape example using the switch expression:
using System;
public class SwitchStatement
{
static string GetShapeType(string shape)
{
return shape switch
{
"circle" => "This is a circle",
"rectangle" => "This is a rectangle",
"triangle" => "This is a triangle",
_ => "Unknown shape"
};
}
public static void Main(string[] args)
{
string shape = "circle";
Console.WriteLine(GetShapeType(shape));
}
}
In this example, the switch expression allows us to define a method (GetShapeType) with a concise syntax, enhancing code brevity without sacrificing readability.
Switching on Enums
Enums, short for enumerations, are a powerful feature in C# for defining a set of named integral constants. The switch statement pairs exceptionally well with enums, providing an elegant solution for handling different states or types.
Let’s consider a simple example with a traffic light enum:
using System;
public enum TrafficLight
{
Red,
Yellow,
Green
}
public class SwitchStatement
{
public static void Main(string[] args)
{
TrafficLight currentLight = TrafficLight.Green;
switch (currentLight)
{
case TrafficLight.Red:
Console.WriteLine("Stop!");
break;
case TrafficLight.Yellow:
Console.WriteLine("Prepare to stop");
break;
case TrafficLight.Green:
Console.WriteLine("Go!");
break;
default:
Console.WriteLine("Invalid traffic light state");
break;
}
}
}
This example showcases how switch statements can effectively handle different states defined by an enum, promoting code readability and maintainability.
Fall-Through Behavior: When You Need It
While fall-through behavior is generally avoided, there are cases where intentional fall-through can be useful. For instance, when multiple cases should execute the same code block, you can omit the break statement intentionally.
using System;
public class SwitchStatement
{
public static void Main(string[] args)
{
char grade = 'B';
switch (grade)
{
case 'A':
case 'B':
Console.WriteLine("Well done!");
break;
case 'C':
Console.WriteLine("Passing");
break;
default:
Console.WriteLine("Needs improvement");
break;
}
}
}
In this example, both ‘A’ and ‘B’ cases share the same code block. If the break statement were included after the ‘A’ case, the ‘B’ case would be unreachable.
Null Cases: Handling Nullable Values
Dealing with null values is a common challenge in programming. The switch statement in C# provides an elegant solution for handling nullable types.
using System;
public class SwitchStatement
{
public static void Main(string[] args)
{
string fruit = null;
switch (fruit)
{
case "Apple":
Console.WriteLine("It's an apple.");
break;
case "Orange":
Console.WriteLine("It's an orange.");
break;
case null:
Console.WriteLine("It's null.");
break;
default:
Console.WriteLine("It's some other fruit.");
break;
}
}
}
In this example, the case null is explicitly defined to handle the scenario where fruit is null. This ensures that the appropriate code block is executed, providing a clean and readable way to handle nullable values.
Conclusion
In conclusion, the switch statement is a powerful tool in the C# programming language for handling multiple conditions. Whether you’re working with simple values, ranges, or complex patterns, the switch statement provides a clean and efficient way to make decisions in your code.
As you continue to explore C# and its features, mastering the switch statement will undoubtedly contribute to writing clearer, more maintainable, and efficient code. Keep these examples in mind, and don’t hesitate to leverage the versatility of the switch statement in your future C# projects.
Related: