DEV Community

Cover image for In C#, how do I remove switch expressions?
Rahul Kumar Jha
Rahul Kumar Jha

Posted on

In C#, how do I remove switch expressions?

Introduction

A number of online discussions can be found regarding the drawbacks of switch expressions or the recommendation to avoid using them altogether.

Several of us have likely received feedback on our pull requests urging us to eliminate switch expressions.

Here are some interesting discussions and blogs to check out:

Switch statements are bad?
Eliminating switch statements
Code Smells, Switch Statement

The purpose of this article is not to emphasize the pros and cons of using switch expressions.

Instead, let's explore how we can restructure our code to eliminate switch expressions if necessary.

Code Setup

We begin by creating a basic console application that associates habits with pets.

Let's add a class named Habit:

public class Habit
{
    public bool PlayFool { get; set; } = true;
    public bool Shy { get; set; } = true;
    public bool LoveColdShowers { get; set; } = true;
    public bool Lazy { get; set; } = false;
    public bool Bite { get; set; } = true;
    public bool Valid { get; set; } = true;
}
Enter fullscreen mode Exit fullscreen mode

It consists of simple boolean properties like Shy and Lazy.

The next step is to add the enum Pet:

public enum Pet
{
    None,
    Cat = 1,
    Dog = 2,
    Rabbit = 3
}
Enter fullscreen mode Exit fullscreen mode

Moving forward, let's introduce a class called PetsHabit which contains public methods for retrieving the pet's habits:

public class PetsHabit
{
    public Habit MapHabitsUsingSwitch(Pet pet)
    {
        return pet switch
        {
            Pet.Dog => new Habit
            {
                LoveColdShowers = false,
                Shy = false
            },
            Pet.Cat => new Habit
            {
                LoveColdShowers = false,
                Lazy = true,
                Shy = false,
            },
            Pet.Rabbit => new Habit
            {
                PlayFool = false,
                Lazy = true,
            },
            _ => new Habit { Valid = false }
        };
    }
}
Enter fullscreen mode Exit fullscreen mode

PetsHabit includes the method MapHabitsUsingSwitch which takes a single parameter of type Pet.

MapHabitsUsingSwitch returns the pet's habit and relies on a switch expression to generate a new habit.

Next, let's investigate alternative approaches to refactoring from switch expressions while maintaining the same logic.

Refactoring Switch Expression with If

Although we can refactor the switch expression into if statements, it's not the best choice.

Nevertheless, for the sake of exploration, let's consider how we can transition from switch expressions to if statements.

Now, let's add another method called MapHabitsUsingIf in the PetsHabit:

public Habit MapHabitsUsingIf(Pet pet)
{
    if (pet is Pet.Dog)
    {
        return new Habit
        {
            LoveColdShowers = false,
            Shy = false
        };
    }

    if (pet is Pet.Cat)
    {
        return new Habit
        {
            LoveColdShowers = false,
            Lazy = true,
            Shy = false,
        };
    }

    if (pet is Pet.Rabbit)
    {
        return new Habit
        {
            PlayFool = false,
            Lazy = true,
        };
    }

    return new Habit { Valid = false };

}
Enter fullscreen mode Exit fullscreen mode

Instead of utilizing a switch expression, MapHabitsUsingIf employs if statements to determine the pet's habit.

Certainly, if we need to refactor from switch expressions, substituting them with if statements is not the optimal solution.

This approach may introduce similar or even more drawbacks.

We must find a better approach - let's examine that in the following section.

Switch Expression Refactoring with Delegate

There are various ways to refactor switch expressions, but the most common suggestion we encounter online is to utilize a strategy pattern.

public class PetsHabit
{
    public Habit MapHabitsUsingDelegate(Pet pet)
    {
        var habitsToFunctionMapper = GetHabitFunction(pet);

        if ( habitsToFunctionMapper.TryGetValue (
             pet, 
             out var getHabitFunbction)
           )
        {
            return getHabitFunbction();
        }
        return new Habit { Valid = false };
    }

    private Dictionary<Pet, Func<Habit>> GetHabitFunction(Pet pet)
    {
        return new Dictionary<Pet, Func<Habit>>
        {
            { Pet.Cat, this.GetCatHabit },
            { Pet.Dog, this.GetDogHabit },
            { Pet.Rabbit, this.GetRabbitHabbit },
        };
    }

}
Enter fullscreen mode Exit fullscreen mode
private Habit GetCatHabit()
{
    return new Habit
    {
        LoveColdShowers = false,
        Lazy = true,
        Shy = false,
    };
}
Enter fullscreen mode Exit fullscreen mode
private Habit GetDogHabit()
{
    return new Habit
    {
        LoveColdShowers = false,
        Shy = false
    };
}
Enter fullscreen mode Exit fullscreen mode
private Habit GetRabbitHabbit()
{
    return new Habit
    {
        PlayFool = false,
        Lazy = true,
    };
}
Enter fullscreen mode Exit fullscreen mode

Top comments (2)

Collapse
 
sinni800 profile image
sinni800

Probably too complex for no benefit. Now you need to decode that "Habit" when reading it instead of seeing it plain in the switch state.

Maybe if you need a million habits, but this is honestly not good.

Collapse
 
sam1221 profile image
Sam

Great knowledge in dotNet and CSharp.
Let's get connected..