0

Here's my scenario:

I have ~100,000 string[] going into a function called CallCommand(string[] command). I have ~50 static classes, that all contain the same method: public static void ParseCommand(string[] command).

My CallCommand function checks the first parameter of the string[] and calls the correct class's ParseCommand.

I'm trying to find a way to call the right function automatically (using generics?) without a switch statement.

Currently, I'm using a large switch statement like so (only showing a few since there are ~50):

public static void CallCommand(string[] command)
{
    string commandVerb = command.First().ToLower();

    switch (commandVerb)
    {
        case "add":
            AddCommand.ParseCommand(command);
            break;
        case "attach":
            AttachCommand.ParseCommand(command);
            break;
        case "assign":
            AssignCommand.ParseCommand(command);
            break;
        case "cancel":
            RunCommand.ParseCommand(command);
            break;
        case "center":
            CenterCommand.ParseCommand(command);
            break;
        case "complain":
            ComplainCommand.ParseCommand(command);
            break;
        default:
            Log("This command doesn't exist.");
            break;
    }
}

I wanted to reduce the code a bit, so I tried using a Dictionary<string, Action> instead (again, reduced the number of key/value pairs here since there's ~50):

private static readonly Dictionary<string, Action<string[]>> handlers = new Dictionary<string, Action<string[]>
{
    ["add"] = new Action<string[]>(AddCommand.ParseCommand),
    ["assign"] = new Action<string[]>(AssignCommand.ParseCommand),
    ["attach"] = new Action<string[]>(AttachCommand.ParseCommand),
    ["cancel"] = new Action<string[]>(AddCommand.ParseCommand),
    ["center"] = new Action<string[]>(AddCommand.ParseCommand),
    ["complain"] = new Action<string[]>(ComplainCommand.ParseCommand)
};

Here's the CallCommand function after setting up the dictionary:

public static void CallCommand(string[] command)
{
    string commandVerb = command.First().ToLower();
    handlers[commandVerb].Invoke(command);
}

Finally, here's an example of one of my static classes. They are all set up exactly the same way. They just do different things in their ParseCommand method:

public static class AssignCommand
{
    public static void ParseCommand(string[] command)
    {
        //do stuff with command
    }
}

I understand I would have to refactor my static classes a bit to achieve what I want (if it's possible), I've just been unable to figure out the correct way.

pfinferno
  • 1,779
  • 3
  • 34
  • 62
  • 1
    What's wrong with the dictionary approach? There's not much room for improvement over something like that. You might add functionality to allow the dictionary to be generated automatically, using reflection, but other than that, what's wrong with what you have? It's not at all clear what your actual *question* is here. – Peter Duniho Sep 26 '19 at 03:58
  • I don't think your `switch` is bad. Most lexers/parsers will have huge `switch` blocks to handle a token. If you don't like this approach, you can always create an interface e.g. `IParser`, let every command implement this and get it injected using DI then find the appropriate concrete class for the verb you want to parse. – JohanP Sep 26 '19 at 03:59
  • I guess I'm finding it annoying to have to remember to add to the switch statement or dictionary every time I create a new command class. I was thinking there might be a way, if I had every command class implement the same interface and have a string property matching the first string parameter, I would only need one line of code. – pfinferno Sep 26 '19 at 04:02
  • Dictionary approach seems better. Alternatively, if your `command.First()` string matches with a Class name then you can implement the solution like this https://stackoverflow.com/a/1044474/2669814 – lkdhruw Sep 26 '19 at 04:05
  • 3
    _"I'm finding it annoying to have to remember to add to the switch statement or dictionary"_ -- reflection-based approach would avoid that. you can look up the type based on the string, for example (e.g. `Type.GetType(commandVerb[0].ToUpperInvariant() + commandVerb.Substring(1) + "Command")` and then get the `ParseCommand()` method from that type), or you can use `Assembly.GetTypes()` to enumerate all the types in the assembly and build a dictionary of the ones where the type name ends with `"Command"`. A hybrid approach would memoize the per-call method lookup. There are lots of options. – Peter Duniho Sep 26 '19 at 04:09
  • But the bottom line here is that _it's not clear what you're asking_. We know you're annoyed. But, have you done anything to try to address that annoyance? If so, what? What research have you done already? What have you tried already? Why didn't that work? What _specifically_ is it you need help with? Please clarify the question by [editing the question](https://stackoverflow.com/posts/58109290/edit) and adding the necessary details. – Peter Duniho Sep 26 '19 at 04:11
  • What Peter says + can you change input or is it fixed to string? – Fildor Sep 26 '19 at 07:08
  • The input is fixed to a string. I like the suggestion @PeterDuniho brought up with reflection. – pfinferno Sep 26 '19 at 13:16
  • Keep in mind that the reflection based approach is maybe two orders of magnitude slower than a `switch` or a dictionary lookup. – dymanoid Sep 26 '19 at 13:23
  • With respect to @dymanoid's note: the cost of the reflection calls is why even with reflection, you will likely want to involve a dictionary as I noted in my comment (i.e. scanning on initialization, or memoizing, rather than doing the reflection lookup on every call). – Peter Duniho Sep 26 '19 at 14:47

0 Answers0