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.
SHARE: