我正在尝试编写一个动态类型的命令行处理器,其中我有一个字典,其中键是可能的参数,而成员是一个Action,其中字符串是在命令行上传递的参数之间的文本。希望能够通过添加params数组并在字典中编写动作来添加参数。
是的,我意识到这是一个过于复杂的实施,以简化维护,这是毫无意义的练习。大多只是试图强调自己学习更多linq。
这是我的字典:
private static Dictionary<string[], Action<string>> _commandLineParametersProcessor = new Dictionary<string[], Action<string>>()
{
{
new string[] {"-l", "--l", "-log", "--log"},
(logFile) =>
{
_blaBla.LogFilePath = logFile;
}
},
{
new string[] { "-s", "--s", "-server", "--server" },
(server) =>
{
ExecuteSomething(server);
_blaBla.Server = server;
}
}
};
采用string [] args的最优雅机制是什么,而不只是关联任何字典键数组中的成员,而是聚合((x,y)=&gt; string.Format(“{0} { 1}“,x,y))在任何键数组中包含()编辑的args []成员之间的元素序列(正在思考TakeWhile()在某种程度上适合这里),并将它们交给动作相应的键值成员。
我们已经无数次地编写了这些小命令行处理器,虽然显然一个简单的循环和切换总是绰绰有余,但这又是我所说的练习强调我的linq技能。所以请不要抱怨我过度工程,那部分是显而易见的。
更新: 为了使这可能更容易一些,这是一种非linq方式来做我正在寻找的东西(可能是不完美的,这只是它的翅膀):
Action<string> currentAction;
string currentActionParameter;
for(int i = 0; i < e.Args.Length; i++)
{
bool isParameterSwitch = _commandLineParametersProcessor.Keys.Any((parameterChoices) => parameterChoices.Contains(e.Args[i]));
if (isParameterSwitch)
{
if (!string.IsNullOrEmpty(currentActionParameter) && currentAction != null)
{
currentAction(currentActionParameter);
currentAction = null;
currentActionParameter = "";
}
currentAction = _commandLineParametersProcessor[_commandLineParametersProcessor.Keys.Single((parameterChoices) => parameterChoices.Contains(e.Args[i]))];
}
else
{
currentActionParameter = string.Format("{0} {1}", currentActionParameter, e.Args[i]);
}
}
这不是一个完全糟糕的方法,我只是想知道是否有人可以使用linq或其他方式稍微简化它,虽然这可能是我猜的最简单的形式..
答案 0 :(得分:2)
假设您知道每个命令都有相应的参数(因此'args'将始终采用
的格式cmd arg (repeated)
你可以做这样荒谬的事......
var output = args.Select((value, idx) => new { Value = value, Group = idx / 2 })
.GroupBy(x => x.Group)
.Select(g => new
{
Command = commands.FirstOrDefault(kvp =>
kvp.Key.Contains(g.First().Value)).Value,
Argument = g.Last().Value
})
.Where(c => c.Command != null)
.Aggregate(
new StringBuilder(),
(builder, value) =>
{
builder.AppendLine(value.Command(value.Argument));
return builder;
}).ToString();
但坦率地说,这是C#中最让我记忆深刻的一点,而且不是一个非常好的方法来教自己LINQ。尽管如此,它会做你要求的。
修改强>
刚刚意识到(感谢David B)您的密钥是string[]
,而不仅仅是string
,所以我添加了一些更加迟钝的代码来处理
答案 1 :(得分:2)
借用Adam Robinson的答案的一半(+1 btw),但是意识到字词永远不会被键访问,而你只想运行Actions而不是构建一个字符串......
var inputCommands = args
.Select((value, idx) => new { Value = value, Group = idx / 2 })
.GroupBy(x => x.Group)
.Select(g => new
{
Command = g.First().Value,
Argument = g.Last().Value
}).ToList();
inputCommands.ForEach(x =>
{
Action<string> theAction =
(
from kvp in commands
where kvp.Key.Contains(x.Command)
select kvp.Value
).FirstOrDefault();
if (theAction != null)
{
theAction(x.Argument);
}
}
kvp.Key.Contains
确实击败了词典的全部内容。我重新设计成Dictionary<string, Action<string>>
。然后你可以说
inputCommands.ForEach(x =>
{
if (commands.ContainsKey(x.Command))
{
commands[x.Command](x.Argument);
}
}
PS:我记得我写的C#代码比我写的更多。
我必须承认你想要收集行动的可能性,而不是运行它们。这是代码:
var todo =
(
from x in inputCommands
let theAction =
(
from kvp in commands
where kvp.Key.Contains(x.Command)
select kvp.Value
).FirstOrDefault()
where theAction != null
select new { TheAction = theAction, Argument = x.Argument }
).ToList();