我正在与一个小组合作制作一个需要大量子命令的命令行工具 - 例如:
cmdtool.exe foo 1 2 3
或
cmdtool.exe bar 9 zombies
目前,它是用一个冗长而丑陋的
列表实现的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
我的问题是,有很多重复的代码,并没有很好的概述我们所有的子命令 我知道如何在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)
但是我如何在C#中做得很好?
我已接近这个:
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}}
};
但是初始化我的查找表的语法是不正确的,当我尝试纠正它时,它变得很难看,但仍然没有编译。
这是C#语法的限制吗? - 我不能以漂亮的方式初始化词典和列表?
C#专家怎么会这样做?
@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>());
}
}
我也研究了各种Nuget包,但是它们增加了比IMHO
更多的混乱答案 0 :(得分:1)
我同意C#复杂对象/字典初始化并不像其他语言那样简单。我认为你只需要一次调整即可让你的尝试工作,但是:
private static Dictionary<string, List<object>> m_dCommandFuncs = new Dictionary<string, List<object>> {
{ "foo", new List<object>{1, 3, CommandFoo}},
{ "bar", new List<object>{2, 2, CommandBar}}
};
答案 1 :(得分:1)
您可以定义delegate type delegate int Command(string[] args);
并像这样初始化字典:
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}}
};
正如其他人所说,你必须明确写出你想要新的清单。需要强制转换,因为编译器抱怨它无法将method group
转换为object
。您也可以转发Func<string[],int>
。为避免使用List<object>
,您应该像这样定义新类:
class CommandConfig
{
public int Lower { get; set; }
public int Upper { get; set; }
public Command Command { get; set; }
}
private static Dictionary<string, CommandConfig> m_dCommandFuncs2 = new Dictionary<string, CommandConfig>
{
{"foo", new CommandConfig {Lower = 1, Upper = 3, Command = CommandFoo}},
{"bar", new CommandConfig {Lower = 2, Upper = 2, Command = CommandBar}}
};
Command
仍然是委托类型。