在C#中初始化函数指针和限制的字典

时间:2018-03-21 16:00:23

标签: c# dictionary command-line

我正在与一个小组合作制作一个需要大量子命令的命令行工具 - 例如:

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

更多的混乱

2 个答案:

答案 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仍然是委托类型。