'Advanced' Console Application

39,670

Solution 1

You need several steps to achieve this but it shouldn't be that hard. First you need some kind of parser that parses what you write. To read each command just use var command = Console.ReadLine(), and then parse that line. And execute the command... Main logic should have a base looking this (sort of):

public static void Main(string[] args)
{
    var exit = false;
    while(exit == false)
    {
         Console.WriteLine();
         Console.WriteLine("Enter command (help to display help): "); 
         var command = Parser.Parse(Console.ReadLine());
         exit = command.Execute();
    }
}

Sort of, you could probably change that to be more complicated.

The code for the Parser and command is sort of straight forward:

public interface ICommand
{
    bool Execute();
}

public class ExitCommand : ICommand
{
    public bool Execute()
    {
         return true;
    }
}

public static Class Parser
{
    public static ICommand Parse(string commandString) { 
         // Parse your string and create Command object
         var commandParts = commandString.Split(' ').ToList();
         var commandName = commandParts[0];
         var args = commandParts.Skip(1).ToList(); // the arguments is after the command
         switch(commandName)
         {
             // Create command based on CommandName (and maybe arguments)
             case "exit": return new ExitCommand();
               .
               .
               .
               .
         }
    }
}

Solution 2

I know this is an old question, but I was searching for an answer too. I was unable to find a simple one though, so I built InteractivePrompt. It's available as a NuGet Package and you can easily extend the code which is on GitHub. It features a history for the current session also.

The functionality in the question could be implemented this way with InteractivePrompt:

static string Help(string strCmd)
{
    // ... logic
    return "Help text";
}
static string OtherMethod(string strCmd)
{
    // ... more logic
    return "Other method";
}
static void Main(string[] args)
{
    var prompt = "> ";
    var startupMsg = "BizLogic Interpreter";
    InteractivePrompt.Run(
        ((strCmd, listCmd) =>
        {
            string result;
            switch (strCmd.ToLower())
            {
                case "help":
                    result = Help(strCmd);
                    break;
                case "othermethod":
                    result = OtherMethod(strCmd);
                    break;
                default:
                    result = "I'm sorry, I don't recognize that command.";
                    break;
            }

            return result + Environment.NewLine;
        }), prompt, startupMsg);
}
Share:
39,670
keynesiancross
Author by

keynesiancross

Beginner programmer who likes to try programming things way more complicated than I can do. . .

Updated on March 16, 2020

Comments

  • keynesiancross
    keynesiancross about 4 years

    I'm not sure if this question has been answered elsewhere and I can't seem to find anything through google that isn't a "Hello World" example... I'm coding in C# .NET 4.0.

    I'm trying to develop a console application that will open, display text, and then wait for the user to input commands, where the commands will run particular business logic.

    For example: If the user opens the application and types "help", I want to display a number of statements etc etc. I'm not sure how to code the 'event handler' for user input though.

    Hopefully this makes sense. Any help would be much appreciated! Cheers.

  • keynesiancross
    keynesiancross over 13 years
    but with the Console.ReadLine() method, how do I then code the different permutations of answers etc? For example Console.ReadLine(), if(Console.ReadLine() == "help) { } etc etc
  • keynesiancross
    keynesiancross over 13 years
    Great, thanks. This is definitely the sort of thing I'm looking for
  • keynesiancross
    keynesiancross over 13 years
    Sorry, how does the interface work in this case? I haven't worked with interfaces much, so that may be my issue...
  • Tomas Jansson
    Tomas Jansson over 13 years
    The interface just specify which method a ceratin object should have. With that in place you can define several different objects that inherits from the interface and let your parser create those objects for you. You can change the interface to what ever you feel like, I just did it with a simple Execute that returns true if the program should exit. I can update with a simple command and sample.
  • Tomas Jansson
    Tomas Jansson over 13 years
    that is not a good design since your function is doing ALL the work. You should divide in so every part has one responsibility.
  • HABJAN
    HABJAN over 13 years
    i agree with that, but i figured out that he is looking for code that he can learn from and that is not too much complicated. You are correct that logic should be separated.. At the end both samples your and mine gives a same result.
  • Tomas Jansson
    Tomas Jansson over 13 years
    It definitely has the same result in the end, but I don't think my solution is that more complicated and it is important that you learn how to do things the right way.... even though mine is probably not suitable for everyone but design is something you should think of. I even consider my solution easier since it is much more "fluent" when you read it and you skip all the details if you don't need them. On a high level it s only, read command, parse the command and last execute the command. That is, you can skip the details in how the command is parsed and how it is executed.
  • Tomas Jansson
    Tomas Jansson over 13 years
    Thank you... and one good thing with this solution is that every Command "lives" in their own context sort of. So nothing stops a command from prompting the user with more questions.
  • keynesiancross
    keynesiancross over 13 years
    When using your code though Tomas, when I try to build it I get an error saying that I can't declare an instance of a class (ExitCommand) in a static class... any thoughts?
  • Tomas Jansson
    Tomas Jansson over 13 years
    Not really, I guess you already change the method signature to static for the Parser method. Could you give the exact exception?
  • keynesiancross
    keynesiancross over 13 years
    I'll give that a shot. This is the error: Error 1 'Parse': cannot declare instance members in a static class
  • Tomas Jansson
    Tomas Jansson over 13 years
    Ok, then I think you need to add the static keyword to the Parse method, I updated the code to reflect that before previous comment.
  • Jeancarlo Fontalvo
    Jeancarlo Fontalvo over 7 years
    Hello Mister @TomasJansson, is there a way to do dependency injection for new commands and attach them to the parser?. ^-^ Thanks for reply.
  • Tomas Jansson
    Tomas Jansson over 7 years
    @JeancarloFontalvo, note that the code above was something I wrote in a matter of minutes a couple of years back. What I would do is to add all the commands in a dictionary of string to commands (or command line parser if you need to parse more input to create the command). If you have that in place you should be able to do: dict[commandName](args) instead of the switch/case.
  • Jeancarlo Fontalvo
    Jeancarlo Fontalvo over 7 years
    Yeah Mister @TomasJansson, nice approach. Thanks