0

How to refactor a large switch case statement that changes via a Console.Readline string?

I have read up multiple websites and Stack Overflow posts regarding this but still do not seem to understand nor know if this is the correct way. Still fairly new to c#.

I have a Console.ReadLine which accepts user Input, I also have a switch case which switches based on the User input

string cmd = Console.ReadLine();

switch(cmd) {
case "login":
    //Execute Login Logic here
    break;

case "logout": 
    //Execute Logout logic here
    break;

//etc.etc.
}

I'm expecting there is some better way to refactor this to stop me needing a larger and larger switch case statement, I have been reading about conditional polymorphism although I am unsure if this is correct, Could someone help me to better understand how i would accomplish this?

Exxili
  • 45
  • 8
  • 2
    your question is not clear can explain something more about this, what you are expecting – Sivashankar Jul 31 '19 at 09:53
  • Sorry, I have a potentially very large switch case, that switches via strings, (upward of 50+ commands) and my question: what is the best method/way to refactor such a large switch case? – Exxili Jul 31 '19 at 09:55
  • Think of it this way: On a GUI (like in a WPF app) you would need to create all the buttons for each command and their handling as well. Here instead of having a button that has handling defined, you are defining the handling of each command here. Yes you could use polymorphism but you'd still need to parse the string to the object somewhere. Or you could also use reflection as explained in [this](https://stackoverflow.com/a/540075/9363973) answer to directly run a method from the string input, which I do not recommend – MindSwipe Jul 31 '19 at 09:57

4 Answers4

2

One of the best approach that you can do this kind of scenarios is Command Patten. you can see how to impelement this pattern from these links Command Design Pattern or Command Pattern

Hadi
  • 443
  • 3
  • 15
2

Well, you could store all possible commands in a collection. You also might want to compare in a case insensitive way:

Dictionary<string, Action> Commands = new Dictionary<string, Action>(StringComparer.InvariantCultureIgnoreCase)
        { { "login", Login }, { "logout", Logout } };

void Login()
{
    // your logic...
}
void Logout()
{
    // your logic...
}

Action GetCommand(string commandName)
{
    return Commands.TryGetValue(commandName, out Action action) ? action : null;
}

Now the code becomes concise and simple:

Action command = GetCommand(Console.ReadLine());
if (command != null)
{
    command();
}

If you need commands with a parameter you could store them in a Dictionary<string, Action<Object>>. If you need with different parameters you need multiple dictionaries:

private static readonly Dictionary<string, Action<object>> CommandWithParameter = new Dictionary<string, Action<object>>(StringComparer.InvariantCultureIgnoreCase)
    { { "login", Login }, { "logout", Logout } };

public static void Login(object parameter)
{
    // cast it to string or whatever here if necessary
}
public static void Logout(object parameter)
{
    // cast it to string or whatever here here if necessary
}

and then call it so:

Action<object> command = GetCommand(cmd);
if (command != null)
{
    command(parameter);
}
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • Would you say it's a good idea to use multiple "handlers" e.g. a `UserHandler` and a `PurchaseHandler` which can themselfs determine if they can handle the "request"? I feel like this `Dictionary` is going to be very long and confusing if you put all of the commands in there. With the handlers you could have a list of handlers and you loop through them, ask if they want to handle the request and if yes let them execute it and stop processing the "request". For few commands your solution seems to be great but isn't 50+ commands a bit too much for this approach? – Joelius Jul 31 '19 at 10:22
  • @Joelius: not sure if there are really 50+ commands to be executed without additional arguments. And if you need them you need a different approach anyway. This was just to demonstrate a different way than the switch-case and should be as simple as possible. – Tim Schmelter Jul 31 '19 at 10:26
  • I think for now I am happy enough with this answer, it definitely reduces the switch case and makes the code more concise/tidier! Also reading up about the other answers which seem complex to me, Lots of reading to do! – Exxili Jul 31 '19 at 10:57
  • Sorry one further question, Is there a way to pass arguments to the Action? – Exxili Jul 31 '19 at 11:11
  • @Exxili: Edited answer – Tim Schmelter Jul 31 '19 at 11:30
0

You might want to consider using the chain of responsibility design pattern - https://www.dofactory.com/net/chain-of-responsibility-design-pattern Split the input into logical groups and use command handlers to process the input

AndyB
  • 101
  • 4
0

IMO the better suitable pattern is the

strategy pattern

Theory, C# implementation