Reputation: 132
I have the following statement using switch expression:
var levelType = task switch
{
var t when t.Status == TaskStatus.EXECUTING && t.PlanIDs.Contains(currentPlan.ID) => WorkplaceAssociatedLevelTypes.Critical,
var t when t.Status == TaskStatus.WAITING && t.PlanIDs.Contains(currentPlan.ID) => WorkplaceAssociatedLevelTypes.Warning,
_ => WorkplaceAssociatedLevelTypes.Untyped
};
As we can see the t.PlanIDs.Contains(currentPlan.ID)
repeats twice and I would like to avoid it.
I'm not sure if it's possible to do a nested statement using switch expression.
Something like it bellow:
var levelType = task switch
{
case (task.PlanIDs.Contains(currentPlan.ID))
true:
var t when t.Status == TaskStatus.EXECUTING => WorkplaceAssociatedLevelTypes.Critical,
var t when t.Status == TaskStatus.WAITING => WorkplaceAssociatedLevelTypes.Warning,
_ => WorkplaceAssociatedLevelTypes.Untyped
false: WorkplaceAssociatedLevelTypes.Untyped
};
The code above does not compile, I invented this one just to demonstrate what I looking for.
Using if-else works:
var levelType = WorkplaceAssociatedLevelTypes.Untyped;
if (task.PlanIDs.Contains(currentPlan.ID))
{
if (task.Status == TaskStatus.EXECUTING)
{
levelType = WorkplaceAssociatedLevelTypes.Critical;
}
else if (task.Status == TaskStatus.WAITING)
{
levelType = WorkplaceAssociatedLevelTypes.Warning;
}
}
Upvotes: 5
Views: 2927
Reputation: 134591
The syntax of the switch expression doesn't change just because you want to nest them, it's the same all the way through.
([expr] switch {
[case] => [expr],
})
([expr] switch {
[case] => ([expr] switch {
[case] => [expr]
}),
})
In your case:
var levelType = task.PlanIDs.Contains(currentPlan.ID) switch
{
true => t.Status switch
{
TaskStatus.EXECUTING => WorkplaceAssociatedLevelTypes.Critical,
TaskStatus.WAITING => WorkplaceAssociatedLevelTypes.Warning,
_ => WorkplaceAssociatedLevelTypes.Untyped,
},
_ => WorkplaceAssociatedLevelTypes.Untyped,
};
Though you could probably just use a single switch expression with this:
var levelType = task.Status switch
{
// cases are evaluated in the order they are given
_ when !task.PlanIDs.Contains(currentPlan.ID) => WorkplaceAssociatedLevelTypes.Untyped,
TaskStatus.EXECUTING => WorkplaceAssociatedLevelTypes.Critical,
TaskStatus.WAITING => WorkplaceAssociatedLevelTypes.Warning,
_ => WorkplaceAssociatedLevelTypes.Untyped,
};
Considering you're working with a boolean expression, I might opt to use a conditional expression instead:
var levelType = task.PlanIDs.Contains(currentPlan.ID)
? task.Status switch
{
TaskStatus.EXECUTING => WorkplaceAssociatedLevelTypes.Critical,
TaskStatus.WAITING => WorkplaceAssociatedLevelTypes.Warning,
_ => WorkplaceAssociatedLevelTypes.Untyped,
}
: WorkplaceAssociatedLevelTypes.Untyped;
Upvotes: 10
Reputation: 9824
I think, first of all it is time for the speed rant: https://ericlippert.com/2012/12/17/performance-rant/
There is a decent chance, the compiler or JiT can optimize that 2nd call away. They can add temporary variables just about everywhere. Including between two case statements. After all, this is all little more then a abstraction for conditional jumps and math.
The optimisation does not hesitate to turn a really short switch/case into a nested if-else, for example. And the JiT could even decide that this case is hit so often, it is cheaper to just write bool temp = t.PlanIDs.Contains(currentPlan.ID)
before the switch/case.
For a practical solution: You can always replace a switch/case with a dictionary, or vice versa. Say a Dictionary<SpecialFoldersEnumeration, Action>
processed by a loop would be as valid as a switch/case having been coded out for each Enumeration Value you care for.
But as you do complex checks, the 1st type should propably a delegate that returns bool and takes t as argument.
Upvotes: 2