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.

1
  • 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<K, V>, 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. Commented Sep 1, 2016 at 0:11

5 Answers 5

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.

Sign up to request clarification or add additional context in comments.

Comments

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();
    }
}

Comments

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);
    }
}

Comments

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;
}

1 Comment

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.
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
    }
}
}

1 Comment

See stackoverflow.com/questions/4233536/… for storing functions

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.