C# introduced switch expressions to enhance the use of patterns and pattern matching, making code more concise and readable. Building on the classic switch statement, switch expressions offer a more fluent syntax by allowing developers to directly return values based on pattern matches. In this article, we’ll dive into the syntax, structure, and real-world usage of switch expressions, showcasing their power through a detailed example. Additionally, we’ll include assignments at three levels of difficulty to help you master this concept.
What is a Switch Expression?
Switch expressions combine the functionality of switch statements with expression-bodied members. Unlike traditional switch statements, which execute blocks of code, switch expressions are used to evaluate and return values directly.
Basic Syntax of Switch Expressions
The basic syntax of a switch expression looks like this:
var result = input switch
{
pattern1 => expression1,
pattern2 => expression2,
_ => defaultExpression // Discard pattern as the default case
};
-
input
: The value, tuple, or object being evaluated. -
pattern
: Represents the condition that the input must match. -
expression
: The value returned when the pattern is matched. -
_
(Discard Pattern): Serves as the default case, capturing any unmatched cases.
Key Features of Switch Expressions
- Assigning the Result: The result can be assigned to a variable or returned directly.
- Patterns: Switch expressions support simple, complex, and nested patterns.
- Consistent Return Types: All expressions must return values of compatible types.
- Order of Patterns: More specific patterns must precede general ones to avoid unreachable code errors.
Detailed Example: Calculating Freight Cost with Switch Expressions
Let’s enhance the example to show how switch expressions can be used effectively in a real-world scenario, like calculating freight costs based on different shipping providers and conditions.
Step 1: Define Order and Shipping Provider Classes
We’ll start by defining classes to represent orders and various shipping providers:
public class Order
{
public IShippingProvider ShippingProvider { get; set; }
public decimal OrderWeight { get; set; }
}
public interface IShippingProvider { }
public class SwedishPostalServiceShippingProvider : IShippingProvider
{
public bool IsNextDayDelivery { get; set; }
}
public class DHLShippingProvider : IShippingProvider
{
public bool IsInternational { get; set; }
}
public class FedExShippingProvider : IShippingProvider
{
public bool IsExpress { get; set; }
}
-
Order
: Represents an order, including the shipping provider and order weight. - Shipping Providers: Different providers have specific properties, like next-day delivery, international shipping, or express delivery.
Step 2: Implement the CalculateFreightCost
Method
Now, let’s implement the CalculateFreightCost
method using a switch expression:
public decimal CalculateFreightCost(Order order)
{
var freightCost = order.ShippingProvider switch
{
// Swedish Postal Service: Free for regular delivery
SwedishPostalServiceShippingProvider { IsNextDayDelivery: false } => 0,
// Swedish Postal Service: Higher cost for next-day delivery
SwedishPostalServiceShippingProvider { IsNextDayDelivery: true } => 25,
// DHL: Varies based on international shipping
DHLShippingProvider { IsInternational: true } => 40 + (order.OrderWeight * 1.5m),
DHLShippingProvider { IsInternational: false } => 20 + (order.OrderWeight * 1.0m),
// FedEx: Varies based on express shipping
FedExShippingProvider { IsExpress: true } => 50 + (order.OrderWeight * 2.0m),
FedExShippingProvider { IsExpress: false } => 30 + (order.OrderWeight * 1.2m),
// Default case: Other providers with base cost and weight
_ => 15 + (order.OrderWeight * 1.1m)
};
return freightCost;
}
Step 3: Testing the CalculateFreightCost
Method
We can create a few test cases to demonstrate how the switch expression works:
var regularOrder = new Order
{
ShippingProvider = new SwedishPostalServiceShippingProvider { IsNextDayDelivery = false },
OrderWeight = 5
};
var nextDayOrder = new Order
{
ShippingProvider = new SwedishPostalServiceShippingProvider { IsNextDayDelivery = true },
OrderWeight = 3
};
var internationalDHLOrder = new Order
{
ShippingProvider = new DHLShippingProvider { IsInternational = true },
OrderWeight = 10
};
var expressFedExOrder = new Order
{
ShippingProvider = new FedExShippingProvider { IsExpress = true },
OrderWeight = 8
};
// Calculate freight costs
Console.WriteLine($"Regular Swedish Postal Service: {CalculateFreightCost(regularOrder)}");
Console.WriteLine($"Next-day Swedish Postal Service: {CalculateFreightCost(nextDayOrder)}");
Console.WriteLine($"International DHL: {CalculateFreightCost(internationalDHLOrder)}");
Console.WriteLine($"Express FedEx: {CalculateFreightCost(expressFedExOrder)}");
Explanation
-
Type and Property Patterns:
- For
SwedishPostalServiceShippingProvider
, the expression checks if it is a next-day delivery or not. - For
DHLShippingProvider
, the expression differentiates between international and domestic shipping. - For
FedExShippingProvider
, it evaluates if the delivery is express or standard.
- For
-
Default Case:
- The discard pattern (
_
) handles any unmatched shipping providers by adding a base cost and weight-based cost.
- The discard pattern (
-
Granularity and Order:
- The most specific patterns are placed at the top to prevent general patterns from overshadowing them. For example, next-day delivery for the Swedish Postal Service is checked before regular delivery.
Assignments
Easy Level
-
Task: Modify the
CalculateFreightCost
method to add a new shipping provider calledUPSShippingProvider
. Assume that all UPS deliveries have a base cost of 35 plus an additional 1.3 per unit of weight.-
Hint: Add a new case for
UPSShippingProvider
within the switch expression. - Expected Outcome: Ensure that UPS is included in the freight cost calculation.
-
Hint: Add a new case for
Medium Level
-
Task: Extend the switch expression to handle weekend deliveries for all shipping providers. If it’s a weekend delivery, add an extra charge of 10 to the cost.
-
Hint: Add a new property
IsWeekendDelivery
to theOrder
class, and use a combination of type and property patterns in the switch expression. - Expected Outcome: The calculation should reflect additional charges for weekend deliveries, regardless of the provider.
-
Hint: Add a new property
Difficult Level
-
Task: Refactor the
CalculateFreightCost
method to use nested patterns to differentiate between more complex conditions, such as combining weekend delivery with next-day delivery.- Hint: Use nested patterns to handle cases like "next-day delivery on weekends" or "express delivery internationally."
- Expected Outcome: Your code should correctly calculate different combinations of conditions, using the most granular patterns first.
Final Thoughts
Switch expressions simplify decision-making logic, making code clearer and more maintainable. They offer flexibility with various pattern types (type, property, and recursive patterns), making them ideal for scenarios with complex conditions.
By working through the assignments, you’ll be able to apply switch expressions effectively in your own projects, making your code more robust and easier to maintain. Give it a try and see how it can transform your coding experience!
Top comments (0)