0

I have this C# application i want to work on. It is mostly command based and what I mean with this is that the user enters some type of command and the application simply performs some kind of task.

For example: User can type in a command such as getdate, the application reads this command and simply displays a date.

NOTE: Its going to be console based but my problem, the actual application has about 80 to 100 commands and my question is how to read this command without relying on some verbose if-else statement to check which command was typed in.

Is there a way I can do this or I just have to go with some long if-else statements.

Tasos K.
  • 7,979
  • 7
  • 39
  • 63
Ralph Marvin
  • 149
  • 2
  • 8
  • 2
    It wouldn't necessarily be less verbose, but you could look at using a `switch` statement. You might be able to use something like a `Dictionary`, but I'm not sure how you would wire that to actual code logic in an elegant way, unless the values were `Func` of some type. – Tim Sep 01 '16 at 00:11

5 Answers5

3

There are several options you could take:

  • You could have a hastable of the commands that map to the type to initialize.

    Dictionary<string, Type> Where type maps to the class you initialize.

  • Use Reflection to directly map the command to an object to initialize (via object name or an attribute.

    [Command(Name = "update")]
    public class RunUpdates : ICommand {
    
    }
    
    [Command(Name = "restart")]
    public class RestartServer : ICommand {
    
    }
    

Then use reflection to find the object that implements ICommand with the attribute matching the command name.

lahsrah
  • 9,013
  • 5
  • 37
  • 67
2

Use a simple form of Command Pattern along with some kind of Command Collection.

A simple way to build this would be:

public class MyApp
{
    private readonly Dictionary<string, Action> _commands = new Dictionary<string, Action>();

    public static void Main()
    {
        var program = new MyApp();
        // Run Console Stuff
    }

    public MyApp()
    {
        SetupCommands();
    }

    public void SetupCommands()
    {
        _commands.Add("PrintDate", () => Console.WriteLine(DateTime.Now));
        _commands.Add("PrintMaxOf3And7", () => Console.WriteLine(Math.Max(3, 7)));
    }

    public void ExecuteCommand(string commandName)
    {
        _commands[commandName].Invoke();
    }
}
Silas Reinagel
  • 4,155
  • 1
  • 21
  • 28
2

Use delegate:

public delegate void CommandDelegate(string input);

public Dictionary<string, CommandDelegate> Commands { get; set; }

/// usage
public void InitCommands() 
{
    Commands.Add("showdata", (input) => Console.WriteLine(....));
    ... // other commands
}

public void ExecuteCommand(string userInput) 
{
    var firstWord = userInput.Substring(0, userInput.IndexOf(" "));
    if (Commands.ContainsKey(firstWord)) 
    {
         var command = Commands[firstWord];   
         command(userInput);
    }
}
Daniel Tran
  • 6,083
  • 12
  • 25
1

You could use a dictionary that uses string as keys and methods (either Action, Func or a custom delegate) as value, then you just need to reas the input from the user and use it a key key to get the corresponding action. If the command can have parameters like this command param1 then use string.Split to separate the command from the parameter, then use the command string as key, and when you execute the method pass the other string as parameter (depending of the type of data of the parameter to may need to parse the parameter of the command from string to something else)

The code would look like this:

Using Func:

NOTE: Func requires at least one parameter and a return value.

void Main()
{
    public Dictionary<string, Func<string, int>> commands =
                                   new Dictionary<string, Func<string, int>>();
    commands.Add("getdate", GetDate);

    Console.WriteLine("Enter a command");
    string input = Console.ReadLine(); //<-- Try typing "getdate"
    commands[input].Invoke();
}

public int GetDate(string someParameter)
{
   Console.WriteLine(DateTime.Today);
   return 0;
}

Using Action:

NOTE: Action requires at least one parameter.

void Main()
{
    public Dictionary<string, Action<string>> commands = new Dictionary<string, Action>();
    commands.Add("getdate", GetDate);

    Console.WriteLine("Enter a command");
    string input = Console.ReadLine(); //<-- Try typing "getdate"
    commands[input].Invoke();
}

public void GetDate(string someParameter)
{
   Console.WriteLine(DateTime.Today);
}

Using Custom Delegate:

public delegate double YourDelegate(string param);

void Main()
{
    public Dictionary<string, YourDelegate> commands = 
                                        new Dictionary<string, YourDelegate>();
    commands.Add("getdate", GetDate);

    Console.WriteLine("Enter a command");
    string input = Console.ReadLine(); //<-- Try typing "getdate"
    commands[input].Invoke();
}

public double GetDate(string someParameter)
{
   Console.WriteLine(DateTime.Today);
   return 0.0;
}
Agustin0987
  • 581
  • 6
  • 15
  • Neither `Func` nor `Action` require at least 1 parameter. Both works perfectly fine without any parameter. However, in that specific case, one probably want to pass the remaining of the command as a string. – Phil1970 Sep 01 '16 at 00:38
0

You could use switch, or you could create a Dictionary with question as key and command as value. Suggest you do a ToLower() on both key and input to make it case insensitive, as relying on user to type perfectly will be difficult.

private Dictionary<string,object> commandList = new Dictionary<string,object>();
private void processCommand(){
commandList.Add("showdate",DateTime.Now);
string command = Console.ReadLine();
if(command.Length>0){
    if(commandList.ContainsKey(command);
         object o = commandList[command.ToLower()];
         //do something
    }
}
}
Shannon Holsinger
  • 2,293
  • 1
  • 15
  • 21