This is part 4 in a series of articles.
In this series we’ve already covered switch expressions and one little-known feature is the ability to nest switch expressions.
Suppose we have the following 3 classes:
class SavingsAccount { public decimal Balance { get; set; } } class HomeLoanAccount { public int MonthsRemaining { get; set; } } class ChequingAccount { public decimal NumberOfTimesOverdrawn { get; set; } public int NumberOfAccountHolders { get; set; } }
(Notice that none of the preceding classes are linked by inheritance.)
Suppose we wanted to run a gift card promotional mailing depending on what accounts customers had. We can use pattern matching on the type of object in a switch expression:
decimal CalculatePromotionalGiftCardValue(object account) => account switch { SavingsAccount sa when (sa.Balance > 10_000) => 100, SavingsAccount _ => 0, // all other savings accounts HomeLoanAccount hla when (hla.MonthsRemaining < 12) => 20, HomeLoanAccount _ => 0, // all other home loan accounts ChequingAccount ca when (ca.NumberOfTimesOverdrawn == 0 && ca.NumberOfAccountHolders == 1) => 20, ChequingAccount ca when (ca.NumberOfTimesOverdrawn == 0 && ca.NumberOfAccountHolders == 2) => 40, ChequingAccount ca when (ca.NumberOfTimesOverdrawn == 0 && ca.NumberOfAccountHolders == 3) => 50, ChequingAccount _ => 0, // all other chequing accounts { } => throw new ArgumentException("Unknown account type", paramName: nameof(account)), // all other non-null object types null => throw new ArgumentNullException(nameof(account)) };
Notice in the preceding expression-bodied method containing a switch expression (that’s a mouthful!), that there is a bit of repetition in the ChequingAccount section with the ca.NumberOfTimesOverdrawn == 0 code being repeated. We can replace this section with a nested switch expression:
decimal CalculatePromotionalGiftCardValueNested(object account) => account switch { SavingsAccount sa when (sa.Balance > 10_000) => 100, SavingsAccount _ => 0, HomeLoanAccount hla when (hla.MonthsRemaining < 12) => 20, HomeLoanAccount _ => 0, ChequingAccount ca when (ca.NumberOfTimesOverdrawn == 0) => ca.NumberOfAccountHolders switch { 1 => 20, 2 => 40, 3 => 50, _ => 0 }, ChequingAccount _ => 0, { } => throw new ArgumentException("Unknown account type", paramName: nameof(account)), null => throw new ArgumentNullException(nameof(account)) };
If you want to fill in the gaps in your C# knowledge be sure to check out my C# Tips and Traps training course from Pluralsight – get started with a free trial.