I am working with a group to make a command line tool that takes a lot of sub commands - e.g.:
cmdtool.exe foo 1 2 3
or
cmdtool.exe bar 9 zombies
Currently it is implemented with a long and ugly list of
else if (command == "foo")
{
if (argLength < 3)
{
Console.Error.WriteLine("Error: not enough args for foo");
errorCode = ExitCode.Error;
}
else
{
// Do something useful
}
}
else if (command == "bar")
// repeat everything from foo
My issue with that is that there is a lot of duplicate code and no good overview of all our subcommands
I know how I would do it in python:
def commandFoo(args):
return DoFooStuff(args)
def commandBar(args):
return DoBarStuff(args)
REGULAR_COMMANDS = {
"foo": [1, 3, commandFoo],
"bar": [2, 2, commandBar]
}
def evaluateCommand(cmdString, args):
if cmdString not in REGULAR_COMMANDS:
print("Unknown command:", cmdString)
return False
lower = REGULAR_COMMANDS[cmdString][0]
upper = REGULAR_COMMANDS[cmdString][1]
if not lower <= len(args) <= upper:
print("Wrong number of args for:", cmdString)
return False
func = REGULAR_COMMANDS[cmdString][2]
return func(args)
But how do I do that nicely in C#?
I have come close with this:
private static int CommandFoo(string[] args)
{
Console.Error.WriteLine("FooFOO");
return (int)ExitCode.Success;
}
private static int CommandBar(string[] args)
{
Console.Error.WriteLine("BarBAR");
return (int)ExitCode.Error;
}
private static Dictionary<string, List<object>> m_dCommandFuncs = new Dictionary<string, List<object>> {
{ "foo", {1, 3, CommandFoo}},
{ "bar", {2, 2, CommandBar}}
};
But the syntax for initializing my lookup table is not correct and when I try to correct it, it gets ugly and still doesn't compile.
Is this a limitation in the C# syntax? - that I cannot initialize dictionaries and lists in a pretty way?
How would a C# expert go about this?
Complete Solution as given by @mcbr :
delegate int Command(string[] args);
private static int CommandFoo(string[] args)
{
Console.Error.WriteLine("FooFOO");
return (int)ExitCode.Success;
}
private static int CommandBar(string[] args)
{
Console.Error.WriteLine("BarBAR");
return (int)ExitCode.Error;
}
private static Dictionary<string, List<object>> m_dCommandFuncs = new Dictionary<string, List<object>> {
{ "foo", new List<object>{1, 3, (Command) CommandFoo}},
{ "bar", new List<object>{2, 2, (Command) CommandBar}}
};
if (m_dCommandFuncs.ContainsKey(command))
{
List<object> lLimitsAndFunc = m_dCommandFuncs[command];
int lowerLimit = (int)lLimitsAndFunc[0];
int upperLimit = (int)lLimitsAndFunc[1];
Command commandFunc = (Command) lLimitsAndFunc[2];
if (argLength < lowerLimit || argLength > upperLimit)
{
Console.Error.WriteLine("error: {0}, wrong number of arguments", command);
exitCode = (int)ExitCode.Error;
}
else
{
var segment = new ArraySegment<string>(args, 1, (1 + upperLimit - lowerLimit));
exitCode = commandFunc(segment.ToArray<string>());
}
}
I also looked into various Nuget packages, but they add more clutter than benefits IMHO