Dynamic switch cases
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();
Rimantas Radžiūnas
Updated on June 04, 2022Comments
-
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
, anduser
.admin
would havecreate, delete, modify, show
functions,moderator
-create, modify, show
functions, anduser
-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 over 8 yearsGreat 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 over 8 yearsAll 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 over 8 yearsyou are correct, my point was to focus on a single point to do access control.
-
Ben Voigt over 8 yearsAnd in the process, introduced exactly the type of bug I was worried about. Fixed now :)