Dynamic switch cases

15,474

Solution 1

The dynamic equivalent of a switch-case is a dictionary lookup. For example:

Dictionary<string, Action> userActions = {
        { "create", () => Console.WriteLine("created") },
        { "show", () => Console.WriteLine("showed") } };
Dictionary<string, Action> adminActions = {
        { "create", () => Console.WriteLine("created") },
        { "show", () => Console.WriteLine("showed") },
        { "delete", () => Console.WriteLine("deleted") } };

Dictionary<string, Dictionary<string, Action>> roleCapabilities = {
        { "user", userActions },
        { "administrator", adminActions } };

roleCapabilities[userType][action]();

At runtime, you can easily add and remove allowed actions to each role (group).

In order to implement "default" logic, you'd use something like:

Action actionCall;
if (roleCapabilities[userType].TryGetValue(action, out actionCall)) {
   actionCall();
}
else {
   // this is the "default" block, the specified action isn't valid for that role
}

Solution 2

This is a good candidate for the strategy pattern.

In the strategy pattern, functionality is represented by an object of an interface that can be passed around. Different implementations allow the behaviour to change dynamically.

For example:

interface ConsoleInteractor
{
    void performAction(string action);
}

class UserConsoleInteractor : ConsoleInteractor
{
    public void performAction(string action)
    {
        switch(i)
        {
            case "create": 
                Console.WriteLine("Created");
                break;
            case "show":
                Console.WriteLine("Showed");
                break;
            default: 
                Console.WriteLine("Default");
                break;
        }
    }
}

Solution 3

Switch (no pun intended) it around do check for role at each case. And then if it is not allowed to do it, skip it.

string i = Console.ReadLine();
if (allowed(userType, i)){
  switch(i):
  case "create": Console.WriteLine("Created");
      handleCreate();
  break;
  case "show":Console.WriteLine("Showed");
      handleShow();
  break;
  case "delete":Console.WriteLine("Deleted");
      handleDelete();
  break;
  default: Console.WriteLine("Default");
    handleDefault(userType);
  break;
}

Solution 4

you are better off with a map of functions or Actions.

var actionsAdmin = new Dictionary<string, Action>{
  {"create", ()=>Console.WriteLine("create")}
  {"modify", ()=>Console.WriteLine("modify")}
}

var actionsUser = new Dictionary<string, Action>{
  {"show", ()=>Console.WriteLine("show")}
  {"foodle", ()=>Console.WriteLine("foodle")}
}

then choose the right map and execute the named function

var action = actionUser[verb];
action();
Share:
15,474
Rimantas Radžiūnas
Author by

Rimantas Radžiūnas

Updated on June 04, 2022

Comments

  • Rimantas Radžiūnas
    Rimantas Radžiūnas almost 2 years

    I'm trying to make a simple switch case console menu for a few different users: admin, moderator, and user. admin would have create, delete, modify, show functions, moderator - create, modify, show functions, and user - create, show functions to choose from.

    Admin switch case:

    if(userType == "admin")
    {
        string i = Console.ReadLine();
        switch(i):
        case "create": Console.WriteLine("Created");
                       break;
        case "modify": Console.WriteLine("Modified");
                       break;
        case "delete":Console.WriteLine("Deleted");
                      break;
        case "show":Console.WriteLine("Showed");
                    break;
        default: Console.WriteLine("Default");
                 break;
    }
    

    Moderator switch case:

    if(userType == "moderator")
    {
        string i = Console.ReadLine();
        switch(i):
        case "create": Console.WriteLine("Created");
                       break;
        case "modify": Console.WriteLine("Modified");
                       break;
        case "show": Console.WriteLine("Showed");
                     break;
        default: Console.WriteLine("Default");
                 break;
    }
    

    User switch case:

    if(userType == "user")
    {
        string i = Console.ReadLine();
        switch(i):
        case "create": Console.WriteLine("Created");
                       break;
        case "show": Console.WriteLine("Showed");
                     break;
        default: Console.WriteLine("Default");
                 break;
    }
    

    Is there any way to mold these switch cases into one dynamic switch? If I'm thinking or explaining something wrong, please correct me.

  • Ben Voigt
    Ben Voigt over 8 years
    Great minds think alike ;) +1 although I think another dictionary to look up the role ("choose the right map" in your words) is useful.
  • Ben Voigt
    Ben Voigt over 8 years
    All that code duplication is asking for trouble. Put the access check outside the switch, and pass in the variable i instead of a string literal. Otherwise you'll someday accidentally code a test for read privilege when performing a mass erase.
  • ergonaut
    ergonaut over 8 years
    you are correct, my point was to focus on a single point to do access control.
  • Ben Voigt
    Ben Voigt over 8 years
    And in the process, introduced exactly the type of bug I was worried about. Fixed now :)